From a17830030e4cc3a204fa8c94a6a2aef4724b2f7c Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Tue, 15 Sep 2015 17:03:36 +0100 Subject: [PATCH 01/11] microbit: HOTFIX: BLE Notification bug in MicroBitDFUService Hotfix of a minor bug in the MicroBitDFU Service that prevented BLE notifications from being sent on the FlashCode characterisitic. Needed as the Samsung companion app is dependent on this functionality to enable BLE programmming of the micro:bit. --- source/MicroBitDFUService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MicroBitDFUService.cpp b/source/MicroBitDFUService.cpp index 729f671..702249f 100644 --- a/source/MicroBitDFUService.cpp +++ b/source/MicroBitDFUService.cpp @@ -234,7 +234,7 @@ void MicroBitDFUService::releaseFlashCode() { flashCode = NRF_FICR->DEVICEID[0]; - ble.updateCharacteristicValue(microBitDFUServiceFlashCodeCharacteristicHandle, (uint8_t *)&flashCode, sizeof(uint32_t)); + ble.gattServer().notify(microBitDFUServiceFlashCodeCharacteristicHandle,(uint8_t *)&flashCode, sizeof(uint32_t)); } /** From 315844520811268cda7f7acca645ded410837141 Mon Sep 17 00:00:00 2001 From: Jonathan Protzenko Date: Wed, 16 Sep 2015 11:46:39 -0700 Subject: [PATCH 02/11] New setAnalogPeriodUs function. Fixes bbc/microbit-extras#1389. --- inc/MicroBitPin.h | 5 +++++ source/MicroBitPin.cpp | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/inc/MicroBitPin.h b/inc/MicroBitPin.h index e4ba2fd..a6381e1 100644 --- a/inc/MicroBitPin.h +++ b/inc/MicroBitPin.h @@ -154,6 +154,11 @@ class MicroBitPin : public MicroBitComponent * @param period The new period for the analog output in milliseconds. */ void setAnalogPeriod(int period); + + /** + * Same thing as setAnalogPeriodUs, but with microseconds. + */ + void setAnalogPeriodUs(int period); }; #endif diff --git a/source/MicroBitPin.cpp b/source/MicroBitPin.cpp index 9d03e8c..17302a5 100644 --- a/source/MicroBitPin.cpp +++ b/source/MicroBitPin.cpp @@ -205,11 +205,18 @@ int MicroBitPin::isTouched() * 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. - */ -void MicroBitPin::setAnalogPeriod(int period) + * @param period The new period for the analog output in microseconds. + */ +void MicroBitPin::setAnalogPeriodUs(int period) { if (status & IO_STATUS_ANALOG_OUT) - ((DynamicPwm *)pin)->setPeriodUs(period*1000); - + ((DynamicPwm *)pin)->setPeriodUs(period); +} + +/** + * Same thing as setAnalogPeriodUs, but with milliseconds. + */ +void MicroBitPin::setAnalogPeriod(int period) +{ + setAnalogPeriodUs(period*1000); } From 78ad8a1646719b5c51fa860ccfb8a71a831af5ae Mon Sep 17 00:00:00 2001 From: Jonathan Protzenko Date: Wed, 16 Sep 2015 12:08:09 -0700 Subject: [PATCH 03/11] Small tweak for the new ignore function. --- inc/MicroBitMessageBus.h | 2 +- source/MicroBitMessageBus.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/inc/MicroBitMessageBus.h b/inc/MicroBitMessageBus.h index fdace6a..a31e7fb 100644 --- a/inc/MicroBitMessageBus.h +++ b/inc/MicroBitMessageBus.h @@ -177,7 +177,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*), void* arg); + void ignore(int id, int value, void (*handler)(MicroBitEvent, void*)); /** * Unregister a listener function. diff --git a/source/MicroBitMessageBus.cpp b/source/MicroBitMessageBus.cpp index 3d7b999..be5c1ff 100644 --- a/source/MicroBitMessageBus.cpp +++ b/source/MicroBitMessageBus.cpp @@ -341,12 +341,13 @@ 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*), void* arg) +void MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent, void*)) { if (handler == NULL) return; - MicroBitListener listener(id, value, handler, arg); + // The remove function is not comparing the [arg] anyhow. + MicroBitListener listener(id, value, handler, NULL); remove(&listener); } From a61bd49620d31d947dbeaf8f7ae95f9f04e720f2 Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Thu, 17 Sep 2015 23:16:40 +0100 Subject: [PATCH 04/11] microbit: BUGFIX: Memory leak in ManagedType.h Corrected corner case memory leak. Instances of ManagedType<> created using the default constructor would create a reference counter by default, with a value of 0. However, if destructor or copy-assigned in this state, this reference count would not be destroyed, resulting in a 4 byte leak on the heap for each occurence. --- inc/ManagedType.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/inc/ManagedType.h b/inc/ManagedType.h index ad28fbd..b43a511 100644 --- a/inc/ManagedType.h +++ b/inc/ManagedType.h @@ -136,7 +136,16 @@ ManagedType::ManagedType(const ManagedType &t) template ManagedType::~ManagedType() { - if (--(*ref) == 0) + // Special case - we were created using a default constructor, and never assigned a value. + if (*ref == 0) + { + // Simply destroy our reference counter and we're done. + free(ref); + } + + // Normal case - we have a valid piece of data. + // Decrement our reference counter and free all allocated memory if we're deleting the last reference. + else if (--(*ref) == 0) { delete object; free(ref); @@ -152,7 +161,14 @@ ManagedType& ManagedType::operator = (const ManagedType&t) if (this == &t) return *this; - if (--(*ref) == 0) + // Special case - we were created using a default constructor, and never assigned a value. + if (*ref == 0) + { + // Simply destroy our reference counter, as we're about to adopt another. + free(ref); + } + + else if (--(*ref) == 0) { delete object; free(ref); From ec30695d7d3cf656387a4af8d427dcf740df7672 Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Thu, 17 Sep 2015 23:32:40 +0100 Subject: [PATCH 05/11] microbit: BUGFIX MicroBit::reset() now operates correctly --- inc/MicroBitPanic.h | 2 +- source/MicroBit.cpp | 12 +++++++++++- source/MicroBitSuperMain.cpp | 9 +-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/inc/MicroBitPanic.h b/inc/MicroBitPanic.h index 1faba60..8a9fac4 100644 --- a/inc/MicroBitPanic.h +++ b/inc/MicroBitPanic.h @@ -11,7 +11,7 @@ void panic(int statusCode); * Resets the micro:bit. * @param statusCode the appropriate status code. Status codes must be in the range 0-255. */ -void reset(int statusCode); +void microbit_reset(); #endif diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index ce3347e..8868374 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -19,6 +19,16 @@ void panic(int statusCode) uBit.panic(statusCode); } +/** + * Perform a hard reset of the micro:bit. + */ +void +microbit_reset() +{ + NVIC_SystemReset(); +} + + /** * Callback when a BLE GATT disconnect occurs. */ @@ -139,7 +149,7 @@ void MicroBit::init() */ void MicroBit::reset() { - reset(); + microbit_reset(); } /** diff --git a/source/MicroBitSuperMain.cpp b/source/MicroBitSuperMain.cpp index 45cc00f..3bbae4c 100644 --- a/source/MicroBitSuperMain.cpp +++ b/source/MicroBitSuperMain.cpp @@ -7,18 +7,11 @@ Serial pc(USBTX, USBRX); MicroBit uBit; InterruptIn resetButton(MICROBIT_PIN_BUTTON_RESET); -void -reset() -{ - NVIC_SystemReset(); -} - - int main() { // Bring up soft reset button. resetButton.mode(PullUp); - resetButton.fall(reset); + resetButton.fall(microbit_reset); #if CONFIG_ENABLED(MICROBIT_DBG) pc.baud(115200); From 9ccdd25e9f2937f43447e771a68492305c2bcbb6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 19 Sep 2015 11:45:45 +0100 Subject: [PATCH 06/11] microbit: Allow to run the idle task within the current fiber's stack. If there is only 1 main fiber (plus the idle fiber) then enabling this new feature for the main fiber (using fiber_allow_run_idle_within()) will mean that no heap is needed to swap the stack out. --- inc/MicroBitFiber.h | 7 +++++++ source/MicroBitFiber.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/inc/MicroBitFiber.h b/inc/MicroBitFiber.h index 8e31f99..b560663 100644 --- a/inc/MicroBitFiber.h +++ b/inc/MicroBitFiber.h @@ -24,6 +24,7 @@ #define MICROBIT_FIBER_FLAG_FOB 0x01 #define MICROBIT_FIBER_FLAG_PARENT 0x02 #define MICROBIT_FIBER_FLAG_CHILD 0x04 +#define MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN 0x08 /** * Thread Context for an ARM Cortex M0 core. @@ -118,6 +119,12 @@ Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void) = releas */ Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *) = release_fiber); +/** + * Allow the idle thread to run within the current thread's stack frame. + * This is useful to prevent paging of the thread's stack to the heap. + */ +void fiber_allow_run_idle_within(); + /** diff --git a/source/MicroBitFiber.cpp b/source/MicroBitFiber.cpp index 636f485..080206c 100644 --- a/source/MicroBitFiber.cpp +++ b/source/MicroBitFiber.cpp @@ -226,6 +226,15 @@ void scheduler_event(MicroBitEvent evt) } } +/** + * Allow the idle thread to run within the current thread's stack frame. + * This is useful to prevent paging of the thread's stack to the heap. + */ +void fiber_allow_run_idle_within() +{ + currentFiber->flags |= MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN; +} + /** * Blocks the calling thread for the given period of time. @@ -622,6 +631,29 @@ void schedule() // Otherwise, just pick the head of the run queue. currentFiber = runQueue; + if (currentFiber == idle && oldFiber->flags & MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN) + { + // Run the idle task right here using the old fiber's stack. + // Keep idling while the runqueue is empty, or there is data to process. + do + { + uBit.systemTasks(); + + if(scheduler_runqueue_empty()) + { + if (uBit.ble) + uBit.ble->waitForEvent(); + else + __WFI(); + } + } + while (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY); + + // Switch to a non-idle fiber. + // If this fiber is the same as the old one then there'll be no switching at all. + currentFiber = runQueue; + } + // Swap to the context of the chosen fiber, and we're done. // Don't bother with the overhead of switching if there's only one fiber on the runqueue! if (currentFiber != oldFiber) From 3cfc7ec6e72dfb711164dba09345b4bb22f8b737 Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Sat, 19 Sep 2015 21:44:58 +0100 Subject: [PATCH 07/11] microbit: Ammendments to ensure fiber is never pages out due to eventing and minor cleanups - renamed fiber flag to be more general. - renamed idle to idleFiber to be consistent with the rest of the code. - factored content of idle() into a funciton to avoid dupication. - added test case to MessageBus::process() to avoid forking fibers if not requested. - removed fiber_allow_run_idle_within mutator in favour of exposing currentFiber, as a more general solution. --- inc/MicroBitFiber.h | 19 +++++---- source/MicroBitFiber.cpp | 74 +++++++++++++++++------------------ source/MicroBitMessageBus.cpp | 2 +- 3 files changed, 46 insertions(+), 49 deletions(-) diff --git a/inc/MicroBitFiber.h b/inc/MicroBitFiber.h index b560663..1de9183 100644 --- a/inc/MicroBitFiber.h +++ b/inc/MicroBitFiber.h @@ -24,7 +24,7 @@ #define MICROBIT_FIBER_FLAG_FOB 0x01 #define MICROBIT_FIBER_FLAG_PARENT 0x02 #define MICROBIT_FIBER_FLAG_CHILD 0x04 -#define MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN 0x08 +#define MICROBIT_FIBER_FLAG_DO_NOT_PAGE 0x08 /** * Thread Context for an ARM Cortex M0 core. @@ -68,6 +68,7 @@ struct Fiber Fiber *next, *prev; // Position of this Fiber on the run queues. }; +extern Fiber *currentFiber; /** * Initialises the Fiber scheduler. @@ -119,13 +120,6 @@ Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void) = releas */ Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *) = release_fiber); -/** - * Allow the idle thread to run within the current thread's stack frame. - * This is useful to prevent paging of the thread's stack to the heap. - */ -void fiber_allow_run_idle_within(); - - /** * Calls the Fiber scheduler. @@ -234,10 +228,15 @@ void queue_fiber(Fiber *f, Fiber **queue); */ void dequeue_fiber(Fiber *f); +/** + * Set of tasks to perform when idle. + * Service any background tasks that are required, and attmept power efficient sleep. + */ +void idle(); + /** * IDLE task. - * Only scheduled for execution when the runqueue is empty. - * Performs a procressor sleep operation, then returns to the scheduler - most likely after a timer interrupt. + * Only scheduled for execution when the runqueue is empty. Typically calls idle(). */ void idle_task(); diff --git a/source/MicroBitFiber.cpp b/source/MicroBitFiber.cpp index 080206c..be6e3a5 100644 --- a/source/MicroBitFiber.cpp +++ b/source/MicroBitFiber.cpp @@ -15,7 +15,7 @@ */ Fiber *currentFiber = NULL; // The context in which the current fiber is executing. Fiber *forkedFiber = NULL; // The context in which a newly created child fiber is executing. -Fiber *idle = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks. +Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks. /* * Scheduler state. @@ -159,9 +159,9 @@ void scheduler_init() // Create the IDLE fiber. // Configure the fiber to directly enter the idle task. - idle = getFiberContext(); - idle->tcb.SP = CORTEX_M0_STACK_BASE - 0x04; - idle->tcb.LR = (uint32_t) &idle_task; + idleFiber = getFiberContext(); + idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04; + idleFiber->tcb.LR = (uint32_t) &idle_task; // Flag that we now have a scheduler running uBit.flags |= MICROBIT_FLAG_SCHEDULER_RUNNING; @@ -226,15 +226,6 @@ void scheduler_event(MicroBitEvent evt) } } -/** - * Allow the idle thread to run within the current thread's stack frame. - * This is useful to prevent paging of the thread's stack to the heap. - */ -void fiber_allow_run_idle_within() -{ - currentFiber->flags |= MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN; -} - /** * Blocks the calling thread for the given period of time. @@ -621,7 +612,7 @@ void schedule() // We're in a normal scheduling context, so perform a round robin algorithm across runnable fibers. // OK - if we've nothing to do, then run the IDLE task (power saving sleep) if (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY) - currentFiber = idle; + currentFiber = idleFiber; else if (currentFiber->queue == &runQueue) // If the current fiber is on the run queue, round robin. @@ -631,21 +622,18 @@ void schedule() // Otherwise, just pick the head of the run queue. currentFiber = runQueue; - if (currentFiber == idle && oldFiber->flags & MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN) + if (currentFiber == idleFiber && oldFiber->flags & MICROBIT_FIBER_FLAG_DO_NOT_PAGE) { // Run the idle task right here using the old fiber's stack. // Keep idling while the runqueue is empty, or there is data to process. + + // Run in the context of the original fiber, to preserve state of flags... + // as we are running on top of this fiber's stack. + currentFiber = oldFiber; + do { - uBit.systemTasks(); - - if(scheduler_runqueue_empty()) - { - if (uBit.ble) - uBit.ble->waitForEvent(); - else - __WFI(); - } + idle(); } while (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY); @@ -659,13 +647,13 @@ void schedule() if (currentFiber != oldFiber) { // Special case for the idle task, as we don't maintain a stack context (just to save memory). - if (currentFiber == idle) + if (currentFiber == idleFiber) { - idle->tcb.SP = CORTEX_M0_STACK_BASE - 0x04; - idle->tcb.LR = (uint32_t) &idle_task; + idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04; + idleFiber->tcb.LR = (uint32_t) &idle_task; } - if (oldFiber == idle) + 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); @@ -681,6 +669,25 @@ void schedule() } } + +/** + * Set of tasks to perform when idle. + * Service any background tasks that are required, and attmept power efficient sleep. + */ +void idle() +{ + // Service background tasks + uBit.systemTasks(); + + // If the above did create any useful work, enter power efficient sleep. + if(scheduler_runqueue_empty()) + { + if (uBit.ble) + uBit.ble->waitForEvent(); + else + __WFI(); + } +} /** * IDLE task. * Only scheduled for execution when the runqueue is empty. @@ -690,16 +697,7 @@ void idle_task() { while(1) { - uBit.systemTasks(); - - if(scheduler_runqueue_empty()) - { - if (uBit.ble) - uBit.ble->waitForEvent(); - else - __WFI(); - } - + idle(); schedule(); } } diff --git a/source/MicroBitMessageBus.cpp b/source/MicroBitMessageBus.cpp index be5c1ff..6e02466 100644 --- a/source/MicroBitMessageBus.cpp +++ b/source/MicroBitMessageBus.cpp @@ -229,7 +229,7 @@ void MicroBitMessageBus::process(MicroBitEvent evt) // Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber // should the event handler attempt a blocking operation, but doesn't have the overhead // of creating a fiber needlessly. (cool huh?) - if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING) + if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING || currentFiber->flags & MICROBIT_FIBER_FLAG_DO_NOT_PAGE) async_callback(l); else invoke(async_callback, l); From 0dcb6834ecd836998e99f23a7231487067e7edfa Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 25 Sep 2015 21:19:10 +0100 Subject: [PATCH 08/11] microbit: Use default constructor for MatrixPoint so data is ROMable. Previous to this patch an explicit constructor was provided for creating MatrixPoint instances, which meant that such objects could not be put in ROM (since they needed to be constructed at runtime). By using the defualt construction method for structs the MatrixPoint map is now compiled into the rodata section, hence freeing up RAM. Saves: 4 bytes data, 56 bytes bss, 148 bytes code. --- inc/MicroBitDisplay.h | 2 -- inc/MicroBitMatrixMaps.h | 52 +++++++++++++++++++------------------- source/MicroBitDisplay.cpp | 11 -------- 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/inc/MicroBitDisplay.h b/inc/MicroBitDisplay.h index c3b5fcd..b499411 100644 --- a/inc/MicroBitDisplay.h +++ b/inc/MicroBitDisplay.h @@ -85,8 +85,6 @@ enum DisplayMode { struct MatrixPoint { uint8_t x; uint8_t y; - - MatrixPoint(uint8_t x, uint8_t y); }; /** diff --git a/inc/MicroBitMatrixMaps.h b/inc/MicroBitMatrixMaps.h index df01ca9..70a2dff 100644 --- a/inc/MicroBitMatrixMaps.h +++ b/inc/MicroBitMatrixMaps.h @@ -19,50 +19,50 @@ #if MICROBIT_DISPLAY_TYPE == MICROBUG_REFERENCE_DEVICE const MatrixPoint MicroBitDisplay::matrixMap[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DISPLAY_ROW_COUNT] = - { {MatrixPoint(0,0),MatrixPoint(0,1),MatrixPoint(0,2), MatrixPoint(0,3), MatrixPoint(0,4)}, - {MatrixPoint(1,0),MatrixPoint(1,1),MatrixPoint(1,2), MatrixPoint(1,3), MatrixPoint(1,4)}, - {MatrixPoint(2,0),MatrixPoint(2,1),MatrixPoint(2,2), MatrixPoint(2,3), MatrixPoint(2,4)}, - {MatrixPoint(3,0),MatrixPoint(3,1),MatrixPoint(3,2), MatrixPoint(3,3), MatrixPoint(3,4)}, - {MatrixPoint(4,0),MatrixPoint(4,1),MatrixPoint(4,2), MatrixPoint(4,3), MatrixPoint(4,4)} + { {{0,0},{0,1},{0,2},{0,3},{0,4}}, + {{1,0},{1,1},{1,2},{1,3},{1,4}}, + {{2,0},{2,1},{2,2},{2,3},{2,4}}, + {{3,0},{3,1},{3,2},{3,3},{3,4}}, + {{4,0},{4,1},{4,2},{4,3},{4,4}} }; #endif #if MICROBIT_DISPLAY_TYPE == MICROBIT_3X9 const MatrixPoint MicroBitDisplay::matrixMap[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DISPLAY_ROW_COUNT] = { - {MatrixPoint(0,4),MatrixPoint(0,3),MatrixPoint(1,1)}, - {MatrixPoint(1,4),MatrixPoint(4,2),MatrixPoint(0,1)}, - {MatrixPoint(2,4),MatrixPoint(3,2),MatrixPoint(4,0)}, - {MatrixPoint(3,4),MatrixPoint(2,2),MatrixPoint(3,0)}, - {MatrixPoint(4,4),MatrixPoint(1,2),MatrixPoint(2,0)}, - {MatrixPoint(4,3),MatrixPoint(0,2),MatrixPoint(1,0)}, - {MatrixPoint(3,3),MatrixPoint(4,1),MatrixPoint(0,0)}, - {MatrixPoint(2,3),MatrixPoint(3,1),MatrixPoint(NO_CONN,NO_CONN)}, - {MatrixPoint(1,3),MatrixPoint(2,1),MatrixPoint(NO_CONN,NO_CONN)} + {{0,4},{0,3},{1,1}}, + {{1,4},{4,2},{0,1}}, + {{2,4},{3,2},{4,0}}, + {{3,4},{2,2},{3,0}}, + {{4,4},{1,2},{2,0}}, + {{4,3},{0,2},{1,0}}, + {{3,3},{4,1},{0,0}}, + {{2,3},{3,1},{NO_CONN,NO_CONN}}, + {{1,3},{2,1},{NO_CONN,NO_CONN}} }; #endif #if MICROBIT_DISPLAY_TYPE == MICROBIT_SB1 const MatrixPoint MicroBitDisplay::matrixMap[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DISPLAY_ROW_COUNT] = { - {MatrixPoint(0,4), MatrixPoint(1,4), MatrixPoint(2,4), MatrixPoint(3,4), MatrixPoint(4,4), MatrixPoint(4,3), MatrixPoint(3,3), MatrixPoint(2,3), MatrixPoint(1,3)}, - {MatrixPoint(0,3), MatrixPoint(4,2), MatrixPoint(3,2), MatrixPoint(2,2), MatrixPoint(1,2), MatrixPoint(0,2), MatrixPoint(4,1), MatrixPoint(3,1), MatrixPoint(2,1)}, - {MatrixPoint(1,1), MatrixPoint(0,1), MatrixPoint(4,0), MatrixPoint(3,0), MatrixPoint(2,0), MatrixPoint(1,0), MatrixPoint(0,0), MatrixPoint(NO_CONN,NO_CONN), MatrixPoint(NO_CONN,NO_CONN)} + {{0,4},{1,4},{2,4},{3,4},{4,4},{4,3},{3,3},{2,3},{1,3}}, + {{0,3},{4,2},{3,2},{2,2},{1,2},{0,2},{4,1},{3,1},{2,1}}, + {{1,1},{0,1},{4,0},{3,0},{2,0},{1,0},{0,0},{NO_CONN,NO_CONN},{NO_CONN,NO_CONN}} }; #endif #if MICROBIT_DISPLAY_TYPE == MICROBIT_SB2 const MatrixPoint MicroBitDisplay::matrixMap[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DISPLAY_ROW_COUNT] = { - {MatrixPoint(0,0),MatrixPoint(4,2),MatrixPoint(2,4)}, - {MatrixPoint(2,0),MatrixPoint(0,2),MatrixPoint(4,4)}, - {MatrixPoint(4,0),MatrixPoint(2,2),MatrixPoint(0,4)}, - {MatrixPoint(4,3),MatrixPoint(1,0),MatrixPoint(0,1)}, - {MatrixPoint(3,3),MatrixPoint(3,0),MatrixPoint(1,1)}, - {MatrixPoint(2,3),MatrixPoint(3,4),MatrixPoint(2,1)}, - {MatrixPoint(1,3),MatrixPoint(1,4),MatrixPoint(3,1)}, - {MatrixPoint(0,3),MatrixPoint(NO_CONN,NO_CONN),MatrixPoint(4,1)}, - {MatrixPoint(1,2),MatrixPoint(NO_CONN,NO_CONN),MatrixPoint(3,2)} + {{0,0},{4,2},{2,4}}, + {{2,0},{0,2},{4,4}}, + {{4,0},{2,2},{0,4}}, + {{4,3},{1,0},{0,1}}, + {{3,3},{3,0},{1,1}}, + {{2,3},{3,4},{2,1}}, + {{1,3},{1,4},{3,1}}, + {{0,3},{NO_CONN,NO_CONN},{4,1}}, + {{1,2},{NO_CONN,NO_CONN},{3,2}} }; #endif diff --git a/source/MicroBitDisplay.cpp b/source/MicroBitDisplay.cpp index 5c71143..4a27b26 100644 --- a/source/MicroBitDisplay.cpp +++ b/source/MicroBitDisplay.cpp @@ -10,17 +10,6 @@ const float timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {0.000010, 0.000047, 0.000094, 0.000187, 0.000375, 0.000750, 0.001500, 0.003000}; -/** - * Constructor. - * Create a Point representation of an LED on a matrix - * Used to handle non-linear matrix layouts. - */ -MatrixPoint::MatrixPoint(uint8_t x, uint8_t y) -{ - this->x = x; - this->y = y; -} - /** * Constructor. * Create a representation of a display of a given size. From 2230e39340779c3450389a0707b37f9e8d03ff6a Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Tue, 29 Sep 2015 23:51:20 +0100 Subject: [PATCH 09/11] microbit: BUGFIX: #1291 ManagedString(INT_MIN) does not work properly Corner case error in serialization code for INT_MIN only - corrected. --- source/MicroBitCompat.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/MicroBitCompat.cpp b/source/MicroBitCompat.cpp index 101cab9..fac127c 100644 --- a/source/MicroBitCompat.cpp +++ b/source/MicroBitCompat.cpp @@ -37,20 +37,20 @@ void string_reverse(char *s) void itoa(int n, char *s) { int i = 0; - int sign = (n >= 0); + int positive = (n >= 0); // Record the sign of the number, // Ensure our working value is positive. - if (!sign) + if (positive) n = -n; // Calculate each character, starting with the LSB. do { - s[i++] = n % 10 + '0'; - } while ((n /= 10) > 0); + s[i++] = abs(n % 10) + '0'; + } while (abs(n /= 10) > 0); // Add a negative sign as needed - if (!sign) + if (!positive) s[i++] = '-'; // Terminate the string. From 85a26dc8e144910e1fd549ad4173c2d40accb40c Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Thu, 8 Oct 2015 14:37:35 +0100 Subject: [PATCH 10/11] microbit: Updates to enable semantic versioning of the micro:bit runtime DAL More specifically, the build system now uses the semantic versioning meta-data held in module.json to define a major.minor.patch version. Additionally, is the branch being compiled is *not* the master branch, the version is appended with . Specific updates: - Updates to CMake files to expose this to the micro:bit runtime code. - Addition of uBit.systemVersion() to expose this to application code. - Displaying of version string over serial if MICROBIT_DBG is enabled. - Distribution of version string over BLE via the firmware revision characteristic. --- inc/MicroBit.h | 8 ++++++++ inc/MicroBitConfig.h | 10 ++++++++++ module.json | 4 ++-- source/CMakeLists.txt | 14 ++++++++++++++ source/MicroBit.cpp | 18 +++++++++++++++--- source/MicroBitSuperMain.cpp | 4 ++++ 6 files changed, 53 insertions(+), 5 deletions(-) diff --git a/inc/MicroBit.h b/inc/MicroBit.h index d7ad736..fd13fb0 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -225,6 +225,14 @@ class MicroBit */ unsigned long systemTime(); + /** + * Determine the version of the micro:bit runtime currently in use. + * + * @return A textual description of the currentlt executing micro:bit runtime. + * TODO: handle overflow case. + */ + char *systemVersion(); + /** * Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided. * diff --git a/inc/MicroBitConfig.h b/inc/MicroBitConfig.h index c2cdcdd..235b90e 100644 --- a/inc/MicroBitConfig.h +++ b/inc/MicroBitConfig.h @@ -243,6 +243,16 @@ #define MICROBIT_HEAP_DBG 0 #endif +// Versioning options. +// We use semantic versioning (http://semver.org/) to identify differnet versions of the micro:bit runtime. +// Where possible we use yotta (an ARM mbed build tool) to help us track versions. +// if this isn't available, it can be defined manually as a configuration option. +// +#ifndef MICROBIT_DAL_VERSION +#define MICROBIT_DAL_VERSION "unknown" +#endif + + // // Helper macro used by the micro:bit runtime to determine if a boolean configuration option is set. // diff --git a/module.json b/module.json index 2f59f22..9d3f5fe 100644 --- a/module.json +++ b/module.json @@ -1,10 +1,10 @@ { "name": "microbit-dal", - "version": "0.0.1", + "version": "1.2.1", "license": "Apache2", "description": "The runtime library for the BBC micro:bit, developed by Lancaster University", "keywords": ["mbed-classic", "microbit", "runtime", "library", "lancaster", "University"], - "author": "James Devine ", + "author": "Joe Finney ", "homepage": "https://developer.mbed.org/teams/Lancaster-University/code/microbit/", "dependencies":{ "mbed-classic": "~0.0.4", diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index abb249c..94a5e2d 100755 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -32,10 +32,24 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES "MemberFunctionCallback.cpp" ) +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") + 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}") +endif() + +set(MICROBIT_DAL_VERSION_FLAGS "-DMICROBIT_DAL_VERSION=\\\"${MICROBIT_DAL_VERSION_STRING}\\\"") + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MICROBIT_DAL_VERSION_FLAGS}") + if (YOTTA_CFG_MICROBIT_CONFIGFILE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${YOTTA_FORCE_INCLUDE_FLAG} \"${YOTTA_CFG_MICROBIT_CONFIGFILE}\"") endif () + if(CMAKE_COMPILER_IS_GNUCC) file(REMOVE "CortexContextSwitch.s") configure_file("CortexContextSwitch.s.gcc" "CortexContextSwitch.s" COPYONLY) diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index 8868374..a38b0e7 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -4,10 +4,10 @@ char MICROBIT_BLE_DEVICE_NAME[] = "BBC MicroBit [xxxxx]"; #if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) && CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) const char MICROBIT_BLE_MANUFACTURER[] = "The Cast of W1A"; -const char MICROBIT_BLE_MODEL[] = "Microbit SB2"; +const char MICROBIT_BLE_MODEL[] = "micro:bit"; const char MICROBIT_BLE_SERIAL[] = "SN1"; const char MICROBIT_BLE_HARDWARE_VERSION[] = "0.2"; -const char MICROBIT_BLE_FIRMWARE_VERSION[] = "1.1"; +const char MICROBIT_BLE_FIRMWARE_VERSION[] = MICROBIT_DAL_VERSION; const char MICROBIT_BLE_SOFTWARE_VERSION[] = "1.0"; #endif @@ -340,7 +340,7 @@ void MicroBit::removeIdleComponent(MicroBitComponent *component) { int i = 0; - while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS) + while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS) i++; if(i == MICROBIT_IDLE_COMPONENTS) @@ -360,6 +360,18 @@ unsigned long MicroBit::systemTime() return ticks; } + +/** + * Determine the version of the micro:bit runtime currently in use. + * + * @return A textual description of the currentlt executing micro:bit runtime. + * TODO: handle overflow case. + */ +char *MicroBit::systemVersion() +{ + return MICROBIT_DAL_VERSION; +} + /** * Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided. * diff --git a/source/MicroBitSuperMain.cpp b/source/MicroBitSuperMain.cpp index 3bbae4c..47fd4a8 100644 --- a/source/MicroBitSuperMain.cpp +++ b/source/MicroBitSuperMain.cpp @@ -16,12 +16,16 @@ int main() #if CONFIG_ENABLED(MICROBIT_DBG) pc.baud(115200); + // For diagnostics. Gives time to open the console window. :-) for (int i=3; i>0; i--) { pc.printf("=== SUPERMAIN: Starting in %d ===\n", i); wait(1.0); } + + pc.printf("micro:bit runtime DAL version %s\n", MICROBIT_DAL_VERSION); + #endif // Bring up our nested heap allocator. From 85b2b1e09ed62cd588b5648aed97304975e29e75 Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Wed, 14 Oct 2015 09:43:57 +0100 Subject: [PATCH 11/11] version v1.2.2 --- module.json | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/module.json b/module.json index 9d3f5fe..7c6fa08 100644 --- a/module.json +++ b/module.json @@ -1,17 +1,24 @@ { "name": "microbit-dal", - "version": "1.2.1", + "version": "1.2.2", "license": "Apache2", "description": "The runtime library for the BBC micro:bit, developed by Lancaster University", - "keywords": ["mbed-classic", "microbit", "runtime", "library", "lancaster", "University"], + "keywords": [ + "mbed-classic", + "microbit", + "runtime", + "library", + "lancaster", + "University" + ], "author": "Joe Finney ", "homepage": "https://developer.mbed.org/teams/Lancaster-University/code/microbit/", - "dependencies":{ + "dependencies": { "mbed-classic": "~0.0.4", "ble": "lancaster-university/BLE_API#master", "ble-nrf51822": "lancaster-university/nrf51822#master" }, - "extraIncludes":[ + "extraIncludes": [ "inc" ] }