Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,62 @@
# Makecode Extension to enable power management on micro:bit (V2)

Use this extension to add all the blocks you will need to power the micro:bit on and off in your program when you are using the [latest micro:bit](https://microbit.org/new-microbit/).
Use this extension to add all the blocks you will need to use less power in your program when you are using the [latest micro:bit](https://microbit.org/new-microbit/).

This extension might be useful when you want to conserve battery power, such as during a data logging activity.


## Usage

### Put the micro:bit to sleep 💤
### Put the micro:bit to sleep in a low power mode 💤

To make the micro:bit sleep, you need to send a request to power it down. The ``||power.powerDownRequest||`` block will ask the micro:bit to power down at the next opportunity, such as when the current code operation has been allowed to complete.
The ``||power.lowPowerRequest||`` block will ask the micro:bit to switch to low power mode at the next opportunity, such as when the current code operation has been allowed to complete, or inside ``||basic.pause(ms)||``.

```blocks
input.onButtonPressed(Button.B, function () {
power.powerDownRequest()
power.lowPowerRequest()
})
```

You can also ask the micro:bit to enter a ``||power.deepSleep||`` where it will pause until a wake up event occurs and power down at the next opportunity.
You can send ``||power.lowPowerRequest(LowPowerMode.Wait)||``. Then micro:bit will also pause until a full power event occurs.

The ``||power.lowPowerPause(ms)||`` block will ask the micro:bit to sleep for a set interval in milliseconds.

The ``||power.deepSleepPause(ms)||`` block will also ask the micro:bit to sleep for a set interval in milliseconds.
In low power mode, the micro:bit is asleep, and your program is paused. When the micro:bit wakes up to full power mode, your program continues from the point it stopped.

You can also use the ``||PowerDown.prevent||`` and ``||PowerDown.allow||`` blocks to block a power down request until the code inside the two blocks has finished running. It is expected that you would use these blocks in pairs.
You can use the ``||power.lowPowerEnable(PowerDown.prevent)||`` and ``||power.lowPowerEnable(PowerDown.allow)||`` blocks to block low power requests until the code between the two blocks has finished running. It is expected that you would use these blocks in pairs.

```blocks
basic.forever(function () {
power.powerDownEnable(PowerDown.prevent)
power.lowPowerEnable(PowerDown.prevent)
led.plot(2, 2)
basic.pause(1000)
led.unplot(2, 2)
led.plot(2, 1)
basic.pause(1000)
led.unplot(2, 1)
power.powerDownEnable(PowerDown.allow)
power.powerDownRequest()
power.lowPowerEnable(PowerDown.allow)
power.lowPowerRequest()
})
```

### Wake the micro:bit from sleep
### Wake up the micro:bit to full power mode

In order to wake the micro:bit, you need to define an event to trigger the wake up call.
In order to wake up the micro:bit to full power mode, you need to define an event to trigger the wake up call.

You can wake the micro:bit when a button or pin is pressed. In this example, the micro:bit will wake up when Button A or Pin 0 has been pressed.

```blocks
power.wakeOnEnable(PowerWakeup.A)
power.wakeOnEnable(PowerWakeup.P0)
power.fullPowerOn(FullPowerSource.A)
power.fullPowerOn(FullPowerSource.P0)
```

You can also wake the micro:bit at a set time interval in milliseconds. In this example, the micro:bit will wake up every minute and show a smiley face on the screen

```blocks
power.wakeEvery(60000, function () {
power.fullPowerEvery(60000, function () {
basic.showIcon(IconNames.Happy)
basic.clearScreen()
power.lowPowerRequest()
})
```

Expand Down
189 changes: 113 additions & 76 deletions power.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,58 +18,77 @@
#endif // MICROBIT_CODAL


enum class PowerWakeup {
enum class FullPowerSource {
//% block="button A"
A = MICROBIT_ID_BUTTON_A,
//% block="button B"
B = MICROBIT_ID_BUTTON_B,
//% block="pin P0"
P0 = MICROBIT_ID_IO_P0,
//% block="pin P1"
P1 = MICROBIT_ID_IO_P1,
//% block="pin P2"
P2 = MICROBIT_ID_IO_P2
};

enum class PowerDown {
prevent,
allow
enum class LowPowerMode {
//% block="continue"
Continue = 0,
//% block="wait"
Wait = 1
};

enum class LowPowerEnable {
//% block="prevent"
Prevent,
//% block="allow"
Allow
};


//% block="Power"
//% icon="\uf011"
//% color=#AA278D
namespace power {

#if MICROBIT_CODAL
int timerEventValue = 1;
#endif // MICROBIT_CODAL

/**
* Pause until a wake up event occurs, and request power down when idle.
*/
//%
void deepSleep() {
#if MICROBIT_CODAL
uBit.power.deepSleep();
#else
uBit.sleep(0);
#endif
}

void lowPowerRequest(LowPowerMode mode = LowPowerMode::Continue);

/**
* Request power down when idle, and return immediately.
* Request low power when the next idle
* @param mode If Continue, then return immediately; if Wait, then pause until a power-up event occurs
*/
//% help=power/low-power-request
//% group="micro:bit (V2)"
//% weight=700
//% block="request low power||and $mode"
//%
void powerDownRequest() {
void lowPowerRequest(LowPowerMode mode) {
#if MICROBIT_CODAL
uBit.power.deepSleepAsync();
if ( mode == LowPowerMode::Wait)
uBit.power.deepSleep();
else
uBit.power.deepSleepAsync();
#else
uBit.sleep(0);
#endif
}
}


/**
* Pause for a fixed interval, and request power down when idle.
* Pause for a fixed interval, and request low power when idle.
* @param interval The period of time to pause, in milliseconds.
*/
//% help=power/low-power-for
//% group="micro:bit (V2)"
//% weight=600
//% interval.shadow=longTimePicker
//% block="request low power for $interval ms"
//%
void deepSleepPause(unsigned interval) {
void lowPowerPause(int interval) {
#if MICROBIT_CODAL
uBit.power.deepSleep(interval);
#else
Expand All @@ -79,38 +98,23 @@ void deepSleepPause(unsigned interval) {


/**
* Do something repeatedy using a wake-up timer.
* @param interval time (in ms) for the timer.
* @param body code to execute
*/
//%
void wakeEvery(unsigned interval, Action body) {
#if MICROBIT_CODAL
registerWithDal( MICROBIT_ID_MAKECODE_POWER, timerEventValue, body);
// CODAL_TIMER_EVENT_FLAGS_WAKEUP makes the timer event trigger power up
system_timer_event_after( 0, MICROBIT_ID_MAKECODE_POWER, timerEventValue, CODAL_TIMER_EVENT_FLAGS_WAKEUP);
system_timer_event_every( interval, MICROBIT_ID_MAKECODE_POWER, timerEventValue++, CODAL_TIMER_EVENT_FLAGS_WAKEUP);
#else
target_panic(PANIC_VARIANT_NOT_SUPPORTED);
#endif
}


/**
* Prevent or allow power down during deepSleep.
* Prevent or allow low power.
* Prevent and allow requests should occur in pairs.
* The default is to allow.
*/
//% help=power/low-power-enable
//% weight=500
//% block="low power %enable"
//%
void powerDownEnable(PowerDown choice) {
void lowPowerEnable(LowPowerEnable enable) {
#if MICROBIT_CODAL
switch ( choice)
switch ( enable)
{
case PowerDown::prevent:
case LowPowerEnable::Prevent:
uBit.power.powerDownDisable();
break;

case PowerDown::allow:
case LowPowerEnable::Allow:
uBit.power.powerDownEnable();
break;

Expand All @@ -122,10 +126,11 @@ void powerDownEnable(PowerDown choice) {


/**
* Determine if power down during deepSleep is enabled
* Determine if low power is enabled
*/
//% help=power/low-power-is-enabled
//%
bool powerDownIsEnabled() {
bool lowPowerIsEnabled() {
#if MICROBIT_CODAL
return uBit.power.powerDownIsEnabled();
#else
Expand All @@ -135,29 +140,55 @@ bool powerDownIsEnabled() {


/**
* Set whether the source should trigger power save wake-up.
* Do something repeatedy with full power using a timer.
* @param interval the time (in ms) for the timer.
* @param code the code to execute
*/
//% help=power/full-power-every
//% group="micro:bit (V2)"
//% weight=800
//% blockAllowMultiple=1
//% interval.shadow=longTimePicker
//% afterOnStart=true
//% block="full power every $interval ms"
//%
void fullPowerEvery(int interval, Action code) {
#if MICROBIT_CODAL
registerWithDal( MICROBIT_ID_MAKECODE_POWER, timerEventValue, code);
// CODAL_TIMER_EVENT_FLAGS_WAKEUP makes the timer event trigger power up
system_timer_event_after( 0, MICROBIT_ID_MAKECODE_POWER, timerEventValue, CODAL_TIMER_EVENT_FLAGS_WAKEUP);
system_timer_event_every( interval, MICROBIT_ID_MAKECODE_POWER, timerEventValue++, CODAL_TIMER_EVENT_FLAGS_WAKEUP);
#else
target_panic(PANIC_VARIANT_NOT_SUPPORTED);
#endif
}


/**
* Set whether the source should trigger full power.
* @param source the source to set
* @param wake true to trigger wake-up or false for no wake-up
* @param enable true to trigger full power
*/
//% help=power/full-power-source-enable
//%
void wakeOn(PowerWakeup source, bool wake) {
void fullPowerSourceEnable(FullPowerSource source, bool enable) {
#if MICROBIT_CODAL
switch ( source)
{
case PowerWakeup::A:
uBit.buttonA.wakeOnActive(wake ? 1 : 0);
case FullPowerSource::A:
uBit.buttonA.wakeOnActive(enable ? 1 : 0);
break;

case PowerWakeup::B:
uBit.buttonB.wakeOnActive(wake ? 1 : 0);
case FullPowerSource::B:
uBit.buttonB.wakeOnActive(enable ? 1 : 0);
break;

case PowerWakeup::P0:
case PowerWakeup::P1:
case PowerWakeup::P2:
case FullPowerSource::P0:
case FullPowerSource::P1:
case FullPowerSource::P2:
{
MicroBitPin *pin = getPin((int)source);
pin->wakeOnActive(wake ? 1 : 0);
pin->wakeOnActive(enable ? 1 : 0);
break;
}
default:
Expand All @@ -168,35 +199,27 @@ void wakeOn(PowerWakeup source, bool wake) {


/**
* Set the source to trigger power save wake-up.
* @param source the source to set
*/
//%
void wakeOnEnable(PowerWakeup source) {
wakeOn(source, true);
}

/**
* Determine if the source will trigger power save wake-up.
* @param source the source to set
* @return true is wake-up is enabled
* Determine if the source will trigger full power.
* @param source the source to check
* @return true if the source will trigger full power
*/
//% help=power/full-power-source-is-enabled
//%
bool wakeOnIsEnabled(PowerWakeup source) {
bool fullPowerSourceIsEnabled(FullPowerSource source) {
#if MICROBIT_CODAL
switch ( source)
{
case PowerWakeup::A:
case FullPowerSource::A:
return uBit.buttonA.isWakeOnActive() ? true : false;
break;

case PowerWakeup::B:
case FullPowerSource::B:
return uBit.buttonB.isWakeOnActive() ? true : false;
break;

case PowerWakeup::P0:
case PowerWakeup::P1:
case PowerWakeup::P2:
case FullPowerSource::P0:
case FullPowerSource::P1:
case FullPowerSource::P2:
{
MicroBitPin *pin = getPin((int)source);
return pin->isWakeOnActive() ? true : false;
Expand All @@ -210,4 +233,18 @@ bool wakeOnIsEnabled(PowerWakeup source) {
}


/**
* Set the source to trigger full power.
* @param source the source to set
*/
//% help=power/full-power-on
//% group="micro:bit (V2)"
//% weight=900
//% block="full power on %source"
//%
void fullPowerOn(FullPowerSource source) {
fullPowerSourceEnable(source, true);
}


} // namespace power
Loading