0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

micro:bit用ステートマシンの見直し ver.0.8.3

Last updated at Posted at 2024-02-03

従来 ver. 0.7.0

課題

ver. 0.7.0 では、次の課題があるので、改善したい。

  1. machine/state
    状態を管理する変数が2つある(machine, state)
  2. 説明の記述方法
    状態名称(遷移を含む)と説明とが1つの引数で記述されている
  3. 複数の遷移先(説明記述)
    遷移先が複数ある場合を想定し、その遷移先を配列で指定できるが、説明の記述も複数必要である
  4. イベント依存
    micro:bitのイベントに依存している
  5. ポーリング間隔
    時間待ちループで、タイムアウトをポーリングしている
ソースコード(ブロック定義)
mstate.ts (ver.0.7.0)
num StateMachines {
    M0 = 0,
    M1,
    M2,
    M3,
    M4,
    M5
}

/**
 * mstate blocks
 * Defining blocks: https://makecode.com/defining-blocks
 * Playground: https://makecode.com/playground
 * icon: a Unicode identifier for an icon from the Font Awesome icon set.
 *       http://fontawesome.io/icons
 */
//% weight=100 color="#4C97FF" icon="\uf362"
//% groups="['Command', 'Declare', 'Transit']"
namespace mstate {

    /**
     * convert state/trigger name (string) to id (number): new id if undefined
     * @param name state name (string) or trigger name (string)
     * @returns state id or trigger id
     */
    //% block="id of $name"
    //% name.defl="a"
    //% weight=210
    //% advanced=true
    export function convId(name: string): number {
    }

    /**
     * Internal event settings
     * @param aStateMachine StateMachines
     * @param eventId Event ID (default: 32868 = 32768 + 100)
     * @param ms Event loop interval (default: 100ms)
     */
    //% block="settings [$aStateMachine] event ID: $eventId every: $ms ms"
    //% aStateMachine.defl=StateMachines.M0
    //% eventId.defl=32768
    //% ms.shadow="timePicker"
    //% ms.defl=100
    //% weight=190
    //% advanced=true
    export function settingsMachineEvent(aStateMachine: StateMachines, eventId: number,
        ms: number
    ) {
    }

    /**
     * define state
     * @param aStateMachine StateMachines
     * @param aStateName state name
     * @param body code to run, (machine: machine ID, state: state ID)
     */
    //% block="define [$machine,$state] to $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% draggableParameters="reporter"
    //% weight=180
    //% group="Declare"
    export function defineState(aStateMachine: StateMachines, aStateName: string,
        body: (machine: number, state: number) => void
    ) {
    }

    /**
     * declare ENTRY action.
     * @param aMachine machine ID
     * @param aState state ID
     * @param body code to run
     */
    //% block="on entry [$aMachine,$aState]"
    //% aMachine.defl=0
    //% aState.defl=0
    //% handlerStatement
    //% weight=170
    //% group="Declare"
    export function declareEntry(aMachine: number, aState: number,
        body: () => void
    ) {
    }

    /**
     * declare DO activity.
     * @param aMachine machine ID
     * @param aState state ID
     * @param aEvery interval time (milliseconds)
     * @param body code to run
     */
    //% block="on do [$aMachine,$aState] every $aEvery ms"
    //% aMachine.defl=0
    //% aState.defl=0
    //% aEvery.shadow="timePicker"
    //% handlerStatement
    //% weight=160
    //% group="Declare"
    export function declareDo(aMachine: number, aState: number, aEvery: number,
        body: () => void
    ) {
    }

    /**
     * declare EXIT action.
     * @param aMachine machine ID
     * @param aState state ID
     * @param body code to run
     */
    //% block="on exit [$aMachine,$aState]"
    //% aMachine.defl=0
    //% aState.defl=0
    //% handlerStatement
    //% weight=150
    //% group="Declare"
    export function declareExit(aMachine: number, aState: number,
        body: () => void
    ) {
    }

    /**
     * declare simple transition.
     * @param aMachine machine ID
     * @param aState state ID
     * @param aTriggerName trigger name
     * @param aToName next state nam
     */
    //% block="trasition [$aMachine,$aState] when $aTriggerName to $aToName"
    //% aMachine.defl=0
    //% aState.defl=0
    //% aTriggerName.defl="e"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=140
    //% group="Transition"
    export function declareSimpleTransition(aMachine: number, aState: number,
        aTriggerName: string, aToName: string
    ) {
    }

    /**
     * declare timeouted transition.
     * @param aMachine machine ID
     * @param aState state ID
     * @param aMs timeout (ms)
     * @param aToName next state name
     */
    //% block="trasition [$aMachine,$aState] timeouted $aMs to $aToName"
    //% aMachine.defl=0
    //% aState.defl=0
    //% aMs.shadow="timePicker"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=130
    //% group="Transition"
    export function declareTimeoutedTransition(aMachine: number, aState: number,
        aMs: number, aToName: string
    ) {
    }

    /**
     * declare custom transition.
     * @param aMachine machine ID
     * @param aState state ID
     * @param aTriggerName trigger name
     * @param aTransList array of next state name 
     * @param body code to run
     */
    //% block="trasition [$aMachine,$aState] when $aTriggerName $args to $aTransList"
    //% aMachine.defl=0
    //% aState.defl=0
    //% aTriggerName.defl="e"
    //% draggableParameters="reporter"
    //% handlerStatement
    //% weight=120
    //% group="Transition"
    export function declareCustomTransition(aMachine: number, aState: number,
        aTriggerName: string, aTransList: string[],
        body: () => void
    ) {
    }

    /**
     * is timeouted.
     * @param aMachine machine ID
     * @param aMs timeout (milliseconds)
     */
    //% block="timeouted [$aMachine] $aMs"
    //% aMachine.defl=0
    //% aMs.shadow="timePicker"
    //% weight=110
    //% group="Transition"
    export function isTimeouted(aMachine: number, aMs: number): boolean {
    }

    /**
     * trigger args.
     * @param aMachine machine ID
     * @returns trigger args
     */
    //% block="trigger args [$aMachine]"
    //% aMachine.defl=0
    //% weight=105
    //% group="Transition"
    //% advanced=true
    export function getTriggerArgs(aMachine: number): number[] {
    }

    /**
     * transit to.
     * @param aMachine machine ID
     * @param index states index]
     */
    //% block="transit [$aMachine] at $index"
    //% aMachine.defl=0
    //% index.defl=0
    //% weight=100
    //% group="Transition"
    export function transitTo(aMachine: number, index: number) {
    }

    /**
     * send trigger
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     */
    //% block="send $aStateMachine $aTriggerName"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=95
    //% group="Command"
    export function send(aStateMachine: StateMachines, aTriggerName: string) {
    }

    /**
     * send trigger with args
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     * @param aTriggerArgs args
     */
    //% block="send $aStateMachine $aTriggerName $aTriggerArgs"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=90
    //% group="Command"
    //% advanced=true
    export function sendWith(aStateMachine: StateMachines, aTriggerName: string,
        aTriggerArgs: number[]
    ) {
    }

    /**
     * start state machine
     * @param aStateMachine StateMachines
     * @param aStateName default state name
     */
    //% block="start $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=80
    //% group="Command"
    export function start(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * export UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aStateMachine
     * @param aStateName default state
     */
    //% block="UML $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=70
    //% group="Command"
    //% shim=mstate::simu_export_uml
    //% advanced=true
    export function exportUml(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * UML state
     * @param aMachine  machine ID
     * @param aStateName state name
     */
    //% block
    //% shim=mstate::simu_state_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuStateUml(aMachine: number, aStateName: string) {
    }

    /**
     * UML transition
     * @param aMachine machine ID
     * @param aState state ID
     * @param aTransList array of next state name
     */
    //% block
    //% shim=mstate::simu_transition_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuTransitionUml(aMachine: number, aState: number,
        aTransList: string[]
    ) {
    }

    /**
     * convert id (number) to state/trigger name (string)
     * @param id state id or trigger id
     * @returns state name (string) or trigger name (string): "[<id>]" if undefined
     */
    //% block
    //% shim=mstate::simu_conv_name
    //% blockHidden=true
    //% advanced=true
    export function _simuConvName(id: number): string {
    }

}

対策 ver. 0.8.0

ブロック定義を試す
次のツールで、MakeCodeのブロック定義を試すことができます。
MakeCode Bolocks Playground - https://makecode.com/playground

課題1. machine/state

従来は、状態を管理する変数や引数が2つあった( machinestate )。
それを、1つにした( mstateId )。

従来版 対策版

image.png

image.png

ソースコード(ブロック定義)
mstate.ts (machine/state)
enum StateMachines {
    M0 = 0,
    M1,
    M2,
    M3,
    M4,
    M5
}

/**
 * mstate blocks
 * Defining blocks: https://makecode.com/defining-blocks
 * Playground: https://makecode.com/playground
 * icon: a Unicode identifier for an icon from the Font Awesome icon set.
 *       http://fontawesome.io/icons
 */
//% weight=100 color="#4C97FF" icon="\uf362"
//% groups="['Command', 'Declare', 'Transit']"
namespace mstate {

    /**
     * convert state/trigger name (string) to id (number): new id if undefined
     * @param aStateMachine StateMachines
     * @param name state name (string) or trigger name (string)
     * @returns machine-state id or machine-trigger id
     */
    //% block="id of $aStateMachine $name"
    //% aStateMachine.defl=StateMachines.M0
    //% name.defl="a"
    //% weight=210
    //% advanced=true
    export function convId(aStateMachine: StateMachines, name: string): number {
    }

    /**
     * Internal event settings
     * @param aStateMachine StateMachines
     * @param eventId Event ID (default: 32868 = 32768 + 100)
     * @param ms Event loop interval (default: 100ms)
     */
    //% block="settings $aStateMachine event ID: $eventId every: $ms ms"
    //% aStateMachine.defl=StateMachines.M0
    //% eventId.defl=32768
    //% ms.shadow="timePicker"
    //% ms.defl=100
    //% weight=190
    //% advanced=true
    export function settingsMachineEvent(aStateMachine: StateMachines, eventId: number,
        ms: number
    ) {
    }

    /**
     * define state
     * @param aStateMachine StateMachines
     * @param aStateName state name
     * @param body code to run, (mstateId: machine-state ID)
     */
    //% block="define $aStateMachine $mstateId to $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% draggableParameters="reporter"
    //% weight=180
    //% group="Declare"
    export function defineState(aStateMachine: StateMachines, aStateName: string,
        body: (mstateId: number) => void
    ) {
    }

    /**
     * declare ENTRY action.
     * @param machine-state ID
     * @param body code to run
     */
    //% block="mstate $aMstateId on entry"
    //% $aMstateId.defl=0
    //% handlerStatement
    //% weight=170
    //% group="Declare"
    export function declareEntry(aMstateId: number,
        body: () => void
    ) {
    }

    /**
     * declare DO activity.
     * @param machine-state ID
     * @param aEvery interval time (milliseconds)
     * @param body code to run
     */
    //% block="mstate $aMstateId on do every $aEvery ms"
    //% aMstateId.defl=0
    //% aEvery.shadow="timePicker"
    //% handlerStatement
    //% weight=160
    //% group="Declare"
    export function declareDo(aMstateId: number, aEvery: number,
        body: () => void
    ) {
    }

    /**
     * declare EXIT action.
     * @param machine-state ID
     * @param body code to run
     */
    //% block="mstate $aMstateId on exit"
    //% aMstateId.defl=0
    //% handlerStatement
    //% weight=150
    //% group="Declare"
    export function declareExit(aMstateId: number,
        body: () => void
    ) {
    }

    /**
     * declare simple transition.
     * @param machine-state ID
     * @param aTriggerName trigger name
     * @param aToName next state nam
     */
    //% block="mstate $aMstateId trasition when $aTriggerName to $aToName"
    //% aMstateId.defl=0
    //% aTriggerName.defl="e"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=140
    //% group="Transition"
    export function declareSimpleTransition(aMstateId: number,
        aTriggerName: string, aToName: string
    ) {
    }

    /**
     * declare timeouted transition.
     * @param machine-state ID
     * @param aMs timeout (ms)
     * @param aToName next state name
     */
    //% block="mstate $aMstateId trasition timeouted $aMs to $aToName"
    //% aMstateId.defl=0
    //% aMs.shadow="timePicker"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=130
    //% group="Transition"
    export function declareTimeoutedTransition(aMstateId: number,
        aMs: number, aToName: string
    ) {
    }

    /**
     * declare custom transition.
     * @param machine-state ID
     * @param aTriggerName trigger name
     * @param aTransList array of next state name 
     * @param body code to run
     */
    //% block="mstate $aMstateId trasition when $aTriggerName $args to $aTransList"
    //% aMstateId.defl=0
    //% aTriggerName.defl="e"
    //% draggableParameters="reporter"
    //% handlerStatement
    //% weight=120
    //% group="Transition"
    export function declareCustomTransition(aMstateId: number,
        aTriggerName: string, aTransList: string[],
        body: () => void
    ) {
    }

    /**
     * is timeouted.
     * @param machine-state ID, as machine ID
     * @param aMs timeout (milliseconds)
     */
    //% block="mstate $aMstateId timeouted $aMs"
    //% aMstateId.defl=0
    //% aMs.shadow="timePicker"
    //% weight=110
    //% group="Transition"
    export function isTimeouted(aMstateId: number, aMs: number): boolean {
    }

    /**
     * trigger args.
     * @param machine-state ID, as machine ID
     * @returns trigger args
     */
    //% block="mstate $aMstateId trigger args"
    //% aMstateId.defl=0
    //% weight=105
    //% group="Transition"
    //% advanced=true
    export function getTriggerArgs(aMstateId: number): number[] {
    }

    /**
     * transit to.
     * @param machine-state ID, as machine ID
     * @param index states index]
     */
    //% block="mstate $aMstateId transit at $index"
    //% aMstateId.defl=0
    //% index.defl=0
    //% weight=100
    //% group="Transition"
    export function transitTo(aMstateId: number, index: number) {
    }

    /**
     * send trigger
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     */
    //% block="send $aStateMachine $aTriggerName"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=95
    //% group="Command"
    export function send(aStateMachine: StateMachines, aTriggerName: string) {
    }

    /**
     * send trigger with args
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     * @param aTriggerArgs args
     */
    //% block="send $aStateMachine $aTriggerName $aTriggerArgs"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=90
    //% group="Command"
    //% advanced=true
    export function sendWith(aStateMachine: StateMachines, aTriggerName: string,
        aTriggerArgs: number[]
    ) {
    }

    /**
     * start state machine
     * @param aStateMachine StateMachines
     * @param aStateName default state name
     */
    //% block="start $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=80
    //% group="Command"
    export function start(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * export UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aStateMachine
     * @param aStateName default state
     */
    //% block="UML $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=70
    //% group="Command"
    //% shim=mstate::simu_export_uml
    //% advanced=true
    export function exportUml(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * UML state
     * @param aMachine  machine ID
     * @param aStateName state name
     */
    //% block
    //% shim=mstate::simu_state_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuStateUml(aMachine: number, aStateName: string) {
    }

    /**
     * UML transition
     * @param aMachine machine ID
     * @param aState state ID
     * @param aTransList array of next state name
     */
    //% block
    //% shim=mstate::simu_transition_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuTransitionUml(aMachine: number, aState: number,
        aTransList: string[]
    ) {
    }

    /**
     * convert id (number) to state/trigger name (string)
     * @param id machine-state id or machine-trigger id
     * @returns state name (string) or trigger name (string): "[<id>]" if undefined
     */
    //% block
    //% shim=mstate::simu_conv_name
    //% blockHidden=true
    //% advanced=true
    export function _simuConvName(id: number): string {
    }

}

課題2. 説明の記述方法

従来は、状態名称に区切り文字で、区切ってUML状態遷移図の説明を記述していた。
その為、状態名称の可読性が失われたり、micro:bit本体での実行時に不具合が生じたりしていた。
それを、新たに追加したブロックで説明を記述するようにした。

説明記述ブロックに続けて、宣言ブロックを配置すると、その宣言ブロックの状態または遷移の説明となる。

対応する宣言ブロック

説明記述ブロックは、次の宣言ブロックに対応します。

  • on entry
  • on do
  • on exit
  • transition
UML 従来版 対策版

image.png

image.png

ソースコード(ブロック定義)
mstate.ts (説明の記述方法)
enum StateMachines {
    M0 = 0,
    M1,
    M2,
    M3,
    M4,
    M5
}

/**
 * mstate blocks
 * Defining blocks: https://makecode.com/defining-blocks
 * Playground: https://makecode.com/playground
 * icon: a Unicode identifier for an icon from the Font Awesome icon set.
 *       http://fontawesome.io/icons
 */
//% weight=100 color="#4C97FF" icon="\uf362"
//% groups="['Command', 'Declare', 'Transit']"
namespace mstate {

    /**
     * convert state/trigger name (string) to id (number): new id if undefined
     * @param aStateMachine StateMachines
     * @param name state name (string) or trigger name (string)
     * @returns machine-state id or machine-trigger id
     */
    //% block="id of $aStateMachine $name"
    //% aStateMachine.defl=StateMachines.M0
    //% name.defl="a"
    //% weight=210
    //% advanced=true
    export function convId(aStateMachine: StateMachines, name: string): number {
    }

    /**
     * Internal event settings
     * @param aStateMachine StateMachines
     * @param eventId Event ID (default: 32868 = 32768 + 100)
     * @param ms Event loop interval (default: 100ms)
     */
    //% block="settings $aStateMachine event ID: $eventId every: $ms ms"
    //% aStateMachine.defl=StateMachines.M0
    //% eventId.defl=32768
    //% ms.shadow="timePicker"
    //% ms.defl=100
    //% weight=190
    //% advanced=true
    export function settingsMachineEvent(aStateMachine: StateMachines, eventId: number,
        ms: number
    ) {
    }

    /**
     * define state
     * @param aStateMachine StateMachines
     * @param aStateName state name
     * @param body code to run, (mstateId: machine-state ID)
     */
    //% block="define $aStateMachine $mstateId to $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% draggableParameters="reporter"
    //% weight=180
    //% group="Declare"
    export function defineState(aStateMachine: StateMachines, aStateName: string,
        body: (mstateId: number) => void
    ) {
    }

    /**
     * declare ENTRY action.
     * @param machine-state ID
     * @param body code to run
     */
    //% block="mstate $aMstateId on entry"
    //% $aMstateId.defl=0
    //% handlerStatement
    //% weight=170
    //% group="Declare"
    export function declareEntry(aMstateId: number,
        body: () => void
    ) {
    }

    /**
     * declare DO activity.
     * @param machine-state ID
     * @param aEvery interval time (milliseconds)
     * @param body code to run
     */
    //% block="mstate $aMstateId on do every $aEvery ms"
    //% aMstateId.defl=0
    //% aEvery.shadow="timePicker"
    //% handlerStatement
    //% weight=160
    //% group="Declare"
    export function declareDo(aMstateId: number, aEvery: number,
        body: () => void
    ) {
    }

    /**
     * declare EXIT action.
     * @param machine-state ID
     * @param body code to run
     */
    //% block="mstate $aMstateId on exit"
    //% aMstateId.defl=0
    //% handlerStatement
    //% weight=150
    //% group="Declare"
    export function declareExit(aMstateId: number,
        body: () => void
    ) {
    }

    /**
     * declare simple transition.
     * @param machine-state ID
     * @param aTriggerName trigger name
     * @param aToName next state nam
     */
    //% block="mstate $aMstateId trasition when $aTriggerName to $aToName"
    //% aMstateId.defl=0
    //% aTriggerName.defl="e"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=140
    //% group="Transition"
    export function declareSimpleTransition(aMstateId: number,
        aTriggerName: string, aToName: string
    ) {
    }

    /**
     * declare timeouted transition.
     * @param machine-state ID
     * @param aMs timeout (ms)
     * @param aToName next state name
     */
    //% block="mstate $aMstateId trasition timeouted $aMs to $aToName"
    //% aMstateId.defl=0
    //% aMs.shadow="timePicker"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=130
    //% group="Transition"
    export function declareTimeoutedTransition(aMstateId: number,
        aMs: number, aToName: string
    ) {
    }

    /**
     * declare custom transition.
     * @param machine-state ID
     * @param aTriggerName trigger name
     * @param aTransList array of next state name 
     * @param body code to run
     */
    //% block="mstate $aMstateId trasition when $aTriggerName $args to $aTransList"
    //% aMstateId.defl=0
    //% aTriggerName.defl="e"
    //% draggableParameters="reporter"
    //% handlerStatement
    //% weight=120
    //% group="Transition"
    export function declareCustomTransition(aMstateId: number,
        aTriggerName: string, aTransList: string[],
        body: () => void
    ) {
    }

    /**
     * is timeouted.
     * @param machine-state ID, as machine ID
     * @param aMs timeout (milliseconds)
     */
    //% block="mstate $aMstateId timeouted $aMs"
    //% aMstateId.defl=0
    //% aMs.shadow="timePicker"
    //% weight=110
    //% group="Transition"
    export function isTimeouted(aMstateId: number, aMs: number): boolean {
    }

    /**
     * trigger args.
     * @param machine-state ID, as machine ID
     * @returns trigger args
     */
    //% block="mstate $aMstateId trigger args"
    //% aMstateId.defl=0
    //% weight=105
    //% group="Transition"
    //% advanced=true
    export function getTriggerArgs(aMstateId: number): number[] {
    }

    /**
     * transit to.
     * @param machine-state ID, as machine ID
     * @param index states index]
     */
    //% block="mstate $aMstateId transit at $index"
    //% aMstateId.defl=0
    //% index.defl=0
    //% weight=100
    //% group="Transition"
    export function transitTo(aMstateId: number, index: number) {
    }

    /**
     * send trigger
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     */
    //% block="send $aStateMachine $aTriggerName"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=95
    //% group="Command"
    export function send(aStateMachine: StateMachines, aTriggerName: string) {
    }

    /**
     * send trigger with args
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     * @param aTriggerArgs args
     */
    //% block="send $aStateMachine $aTriggerName $aTriggerArgs"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=90
    //% group="Command"
    //% advanced=true
    export function sendWith(aStateMachine: StateMachines, aTriggerName: string,
        aTriggerArgs: number[]
    ) {
    }

    /**
     * start state machine
     * @param aStateMachine StateMachines
     * @param aStateName default state name
     */
    //% block="start $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=80
    //% group="Command"
    export function start(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * export UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aStateMachine
     * @param aStateName default state
     */
    //% block="UML $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=70
    //% group="Command"
    //% shim=mstate::simu_export_uml
    //% advanced=true
    export function exportUml(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * description UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aDescription
     */
    //% block="description $aDescription"
    //% aDescription.defl="(description)"
    //% weight=60
    //% group="Command"
    //% shim=mstate::simu_description_uml
    //% advanced=true
    export function descriptionUml(aDescription: string) {
    }
    
    /**
     * UML state
     * @param aMachine  machine ID
     * @param aStateName state name
     */
    //% block
    //% shim=mstate::simu_state_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuStateUml(aMachine: number, aStateName: string) {
    }

    /**
     * UML transition
     * @param aMachine machine ID
     * @param aState state ID
     * @param aTransList array of next state name
     */
    //% block
    //% shim=mstate::simu_transition_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuTransitionUml(aMachine: number, aState: number,
        aTransList: string[]
    ) {
    }

    /**
     * convert id (number) to state/trigger name (string)
     * @param id machine-state id or machine-trigger id
     * @returns state name (string) or trigger name (string): "[<id>]" if undefined
     */
    //% block
    //% shim=mstate::simu_conv_name
    //% blockHidden=true
    //% advanced=true
    export function _simuConvName(id: number): string {
    }

}

課題3. 複数の遷移先(説明の記述)

複数の遷移先がある場合、それぞれの遷移に説明を記述できるようにする為、説明記述ブロックの引数を配列にする(遷移先の配列と順序を合わせる)。
また、説明記述ブロックの引数配列化に伴い、状態の宣言ブロックに対しては、UML出力時に、その要素毎に改行した説明文字列を出力する(改行コード \n )。

UML 対策版

image.png

ソースコード(ブロック定義)
mstate.ts (複数の遷移先)
enum StateMachines {
    M0 = 0,
    M1,
    M2,
    M3,
    M4,
    M5
}

/**
 * mstate blocks
 * Defining blocks: https://makecode.com/defining-blocks
 * Playground: https://makecode.com/playground
 * icon: a Unicode identifier for an icon from the Font Awesome icon set.
 *       http://fontawesome.io/icons
 */
//% weight=100 color="#4C97FF" icon="\uf362"
//% groups="['Command', 'Declare', 'Transit']"
namespace mstate {

    /**
     * convert state/trigger name (string) to id (number): new id if undefined
     * @param aStateMachine StateMachines
     * @param name state name (string) or trigger name (string)
     * @returns machine-state id or machine-trigger id
     */
    //% block="id of $aStateMachine $name"
    //% aStateMachine.defl=StateMachines.M0
    //% name.defl="a"
    //% weight=210
    //% advanced=true
    export function convId(aStateMachine: StateMachines, name: string): number {
    }

    /**
     * Internal event settings
     * @param aStateMachine StateMachines
     * @param eventId Event ID (default: 32868 = 32768 + 100)
     * @param ms Event loop interval (default: 100ms)
     */
    //% block="settings $aStateMachine event ID: $eventId every: $ms ms"
    //% aStateMachine.defl=StateMachines.M0
    //% eventId.defl=32768
    //% ms.shadow="timePicker"
    //% ms.defl=100
    //% weight=190
    //% advanced=true
    export function settingsMachineEvent(aStateMachine: StateMachines, eventId: number,
        ms: number
    ) {
    }

    /**
     * define state
     * @param aStateMachine StateMachines
     * @param aStateName state name
     * @param body code to run, (mstateId: machine-state ID)
     */
    //% block="define $aStateMachine $mstateId to $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% draggableParameters="reporter"
    //% weight=180
    //% group="Declare"
    export function defineState(aStateMachine: StateMachines, aStateName: string,
        body: (mstateId: number) => void
    ) {
    }

    /**
     * declare ENTRY action.
     * @param machine-state ID
     * @param body code to run
     */
    //% block="mstate $aMstateId on entry"
    //% $aMstateId.defl=0
    //% handlerStatement
    //% weight=170
    //% group="Declare"
    export function declareEntry(aMstateId: number,
        body: () => void
    ) {
    }

    /**
     * declare DO activity.
     * @param machine-state ID
     * @param aEvery interval time (milliseconds)
     * @param body code to run
     */
    //% block="mstate $aMstateId on do every $aEvery ms"
    //% aMstateId.defl=0
    //% aEvery.shadow="timePicker"
    //% handlerStatement
    //% weight=160
    //% group="Declare"
    export function declareDo(aMstateId: number, aEvery: number,
        body: () => void
    ) {
    }

    /**
     * declare EXIT action.
     * @param machine-state ID
     * @param body code to run
     */
    //% block="mstate $aMstateId on exit"
    //% aMstateId.defl=0
    //% handlerStatement
    //% weight=150
    //% group="Declare"
    export function declareExit(aMstateId: number,
        body: () => void
    ) {
    }

    /**
     * declare simple transition.
     * @param machine-state ID
     * @param aTriggerName trigger name
     * @param aToName next state nam
     */
    //% block="mstate $aMstateId trasition when $aTriggerName to $aToName"
    //% aMstateId.defl=0
    //% aTriggerName.defl="e"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=140
    //% group="Transition"
    export function declareSimpleTransition(aMstateId: number,
        aTriggerName: string, aToName: string
    ) {
    }

    /**
     * declare timeouted transition.
     * @param machine-state ID
     * @param aMs timeout (ms)
     * @param aToName next state name
     */
    //% block="mstate $aMstateId trasition timeouted $aMs to $aToName"
    //% aMstateId.defl=0
    //% aMs.shadow="timePicker"
    //% aToName.defl="a"
    //% inlineInputMode=inline
    //% weight=130
    //% group="Transition"
    export function declareTimeoutedTransition(aMstateId: number,
        aMs: number, aToName: string
    ) {
    }

    /**
     * declare custom transition.
     * @param machine-state ID
     * @param aTriggerName trigger name
     * @param aTransList array of next state name 
     * @param body code to run
     */
    //% block="mstate $aMstateId trasition when $aTriggerName $args to $aTransList"
    //% aMstateId.defl=0
    //% aTriggerName.defl="e"
    //% draggableParameters="reporter"
    //% handlerStatement
    //% weight=120
    //% group="Transition"
    export function declareCustomTransition(aMstateId: number,
        aTriggerName: string, aTransList: string[],
        body: () => void
    ) {
    }

    /**
     * is timeouted.
     * @param machine-state ID, as machine ID
     * @param aMs timeout (milliseconds)
     */
    //% block="mstate $aMstateId timeouted $aMs"
    //% aMstateId.defl=0
    //% aMs.shadow="timePicker"
    //% weight=110
    //% group="Transition"
    export function isTimeouted(aMstateId: number, aMs: number): boolean {
    }

    /**
     * trigger args.
     * @param machine-state ID, as machine ID
     * @returns trigger args
     */
    //% block="mstate $aMstateId trigger args"
    //% aMstateId.defl=0
    //% weight=105
    //% group="Transition"
    //% advanced=true
    export function getTriggerArgs(aMstateId: number): number[] {
    }

    /**
     * transit to.
     * @param machine-state ID, as machine ID
     * @param index states index]
     */
    //% block="mstate $aMstateId transit at $index"
    //% aMstateId.defl=0
    //% index.defl=0
    //% weight=100
    //% group="Transition"
    export function transitTo(aMstateId: number, index: number) {
    }

    /**
     * send trigger
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     */
    //% block="send $aStateMachine $aTriggerName"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=95
    //% group="Command"
    export function send(aStateMachine: StateMachines, aTriggerName: string) {
    }

    /**
     * send trigger with args
     * @param aStateMachine StateMachines
     * @param aTriggerName trigger name
     * @param aTriggerArgs args
     */
    //% block="send $aStateMachine $aTriggerName $aTriggerArgs"
    //% aStateMachine.defl=StateMachines.M0
    //% aTriggerName.defl="e"
    //% weight=90
    //% group="Command"
    //% advanced=true
    export function sendWith(aStateMachine: StateMachines, aTriggerName: string,
        aTriggerArgs: number[]
    ) {
    }

    /**
     * start state machine
     * @param aStateMachine StateMachines
     * @param aStateName default state name
     */
    //% block="start $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=80
    //% group="Command"
    export function start(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * export UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aStateMachine
     * @param aStateName default state
     */
    //% block="UML $aStateMachine $aStateName"
    //% aStateMachine.defl=StateMachines.M0
    //% aStateName.defl="a"
    //% weight=70
    //% group="Command"
    //% shim=mstate::simu_export_uml
    //% advanced=true
    export function exportUml(aStateMachine: StateMachines, aStateName: string) {
    }

    /**
     * description UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aDescription
     */
    //% block="description $aDescription"
    //% aDescription.defl="(description)"
    //% weight=60
    //% group="Command"
    //% shim=mstate::simu_description_uml
    //% advanced=true
    export function descriptionUml(aDescription: string) {
    }
    
    /**
     * description UML, PlantUML
     * PlantUML Web server: http://www.plantuml.com/plantuml/
     * @param aDescription
     */
    //% block="description $aDescriptionList"
    //% weight=50
    //% group="Command"
    //% shim=mstate::simu_descriptions_uml
    //% advanced=true
    export function descriptionsUml(aDescriptionList: string[]) {
    }
    
    /**
     * UML state
     * @param aMachine  machine ID
     * @param aStateName state name
     */
    //% block
    //% shim=mstate::simu_state_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuStateUml(aMachine: number, aStateName: string) {
    }

    /**
     * UML transition
     * @param aMachine machine ID
     * @param aState state ID
     * @param aTransList array of next state name
     */
    //% block
    //% shim=mstate::simu_transition_uml
    //% blockHidden=true
    //% advanced=true
    export function _simuTransitionUml(aMachine: number, aState: number,
        aTransList: string[]
    ) {
    }

    /**
     * convert id (number) to state/trigger name (string)
     * @param id machine-state id or machine-trigger id
     * @returns state name (string) or trigger name (string): "[<id>]" if undefined
     */
    //% block
    //% shim=mstate::simu_conv_name
    //% blockHidden=true
    //% advanced=true
    export function _simuConvName(id: number): string {
    }

}

課題4. イベント依存

pxt-mstateでは、状態遷移の判定とその実行をmicro:bitのイベント(uBit.messageBus)に依存している。
このイベント処理部分を mcontroller 名前空間の関数群として抜きだし、他の実行環境でも容易に実装できるよう、差し替え可能にする(将来的には抽象クラスとして実現したい)。

TypeScript

    /**
     * controller - micro:bit
     */
    export namespace mcontroller {

        /**
         * idle update
         * @param machineId machine ID
         */
        function _idleUpdate(machineId: number) {
            control.raiseEvent(MSTATE_BUS_ID.MSTATE_ID_UPDATE, machineId)
        }


        /**
         * create StateMachine
         * @param machineId machine ID
         * @returns instance of StateMachine
         */
        function _createNewStateMacnhe(machineId: number) {
            return new mmachine.StateMachine(machineId, function () {
                _idleUpdate(machineId)
            })
        }

    }
    

課題5. ポーリング間隔

(保留)
時間待ちループの経過時間の取得もmicro:bitに依存しているため、外部タイマーとして外出しとし、差し替え可能にしたい。それに合わせて、タイムアウトによるトランジション方式も見直したい。

まとめ

5つの課題のうち、4つの課題を解決し、ver.0.8.3以降 で対応した。
残課題は、次の機会に対応する。

# 課題 結果 残課題
1 machine/state 解決
2 説明の記述方法 解決
3 複数の遷移先(説明記述) 解決
4 イベント依存 解決 抽象クラス化
5 ポーリング間隔 保留 外部タイマー化

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?