View on GitHub

pxt-states

Finite state machine for micro:bit

States

A finite state machine extension for micro:bit. Using state machines can dramatically simplfy control flow code, while improving readbility.

Defining states

States can have enter and exit behaviours as well as behaviours that can be looped while the state is active.

states.setEnterHandler("Waiting", function () {
    
})
states.addLoopHandler("Waiting", function () {
    
})
states.setExitHandler("Waiting", function () {
    
})

Using states

states.setState("Waiting")

Example

states.setEnterHandler("Idle", function () {
    basic.clearScreen()
})
states.addLoopHandler("Idle", function () {
    if (input.lightLevel() < 10) {
        states.setState("Started")
    }
})
states.setEnterHandler("Started", function () {
    basic.showIcon(IconNames.Yes)
})
states.addLoopHandler("Started", function () {
    if (input.buttonIsPressed(Button.A)) {
        states.setState("Idle")
    }
})
states.addLoopHandler("Started", function () {
    led.plotBarGraph(
    input.lightLevel(),
    255
    )
})
states.setState("Idle")

Advanced blocks

Do something whenever state has changed

states.setChangeHandler(function() {})

Get the name of the currently active state

states.currentState()

Get the name of the last active state

states.previousState()

Get the name of the next active state (only works when while exiting a state)

states.nextState()

Return true if the currently active state matches a given name

states.matchCurrent("Waiting")

Return true if the last active state matches a given name

states.matchPrevious("Waiting")

Return true if the next active state matches a given name (only works when while exiting a state)

states.matchNext("Waiting")

Multiple state machines

Multiple independamt state machines can be created by using a “Machine.State” naming convention in all the extension’s blocks.

states.setExitHandler("Sound.Low", function () {
    led.unplot(4, 4)
})
states.addLoopHandler("Sound.High", function () {
    led.toggle(4, 0)
    basic.pause(500)
})
states.addLoopHandler("Sound.Low", function () {
    led.toggle(4, 4)
    basic.pause(500)
})
states.addLoopHandler("Light.High", function () {
    led.toggle(0, 0)
    basic.pause(500)
})
states.setExitHandler("Light.High", function () {
    led.unplot(0, 0)
})
states.addLoopHandler("Light.Low", function () {
    led.toggle(0, 4)
    basic.pause(500)
})
states.setExitHandler("Sound.High", function () {
    led.unplot(4, 0)
})
states.setExitHandler("Light.Low", function () {
    led.unplot(0, 4)
})
basic.forever(function () {
    if (input.lightLevel() > 127) {
        states.setState("Light.High")
    } else {
        states.setState("Light.Low")
    }
    if (input.soundLevel() > 127) {
        states.setState("Sound.High")
    } else {
        states.setState("Sound.Low")
    }
})

Sub-states

Sub states can be created by using a “State.Substate” naming convention. A sub-state can be activated within a state without leaving the parent state. Leaving the parent state will automatically deactivae all its sub-states.

states.addLoopHandler("Playing.Idle", function () {
    led.toggle(2, 2)
    basic.pause(500)
})
states.setEnterHandler("Playing.B", function () {
    basic.clearScreen()
})
states.addLoopHandler("Idle", function () {
    if (input.buttonIsPressed(Button.A)) {
        states.setState("Playing")
    }
})
states.setEnterHandler("Playing.A", function () {
    basic.clearScreen()
})
states.addLoopHandler("Playing.A", function () {
    led.toggle(0, 2)
    basic.pause(500)
})
states.setEnterHandler("Playing.Idle", function () {
    basic.clearScreen()
})
states.addLoopHandler("Playing", function () {
    if (input.buttonIsPressed(Button.A)) {
        states.setState("Playing.A")
    } else if (input.buttonIsPressed(Button.B)) {
        states.setState("Playing.B")
    } else if (input.logoIsPressed()) {
        basic.clearScreen()
        states.setState("Idle")
    } else {
        states.setState("Playing.Idle")
    }
})
states.addLoopHandler("Playing.B", function () {
    led.toggle(4, 2)
    basic.pause(500)
})
states.setState("Idle")

Metadata (used for search, rendering)