ブロックを積みながら(13) micro:bit V2、BLEサービス「積んで」みたけれど

Joseph Halfmoon

BBC micro:bit V2をゲットということで、V1.5の時にはRAM不足でできなかったBLEサービスの「だいたい全部載せ」やってみました。これが出来れば面倒なmicro:bitのペアリング作業を省略できる、と。しかしそうは問屋が卸しませんでした。結論から言えば、1個1個確かめないとね。毎度のペアリング作業ももう慣れましたわい。

※「ブロックを積みながら」投稿順 index はこちら

micro:bitで良く考えられているなと感心する点はいろいろあるのですが、デバイスに書きこむオブジェクトコードもその一つじゃないかと思います。オブジェクトコードのフォーマット自体は「歴史と伝統の」インテルHEXフォーマットです。搭載SoCが異なり、ライブラリ等を切り替える必要があると思われるV1系とV2系のmicro:bitを同時サポートできる優れものです。またオブジェクトファイルと言いつつ、ソースそしてブロック表現まで復元できるところも何気に素晴らしいです。ちょっと脱線すると、昨今のマイコンでHEXフォーマットファイルというと、モトローラSフォーマットの方が優勢かと思うのですが、昔々80系で始まったMicroSoftが作ったためなのかMakeCode環境はインテルHEXです。ちなみにHEXファイルなのでインテルHEXでもモトローラSでもエディタで開けます。そして行頭を見て”:”(コロン)で始まっていればインテルHEX、英文字”S”で始まっていればモトローラSです。型式はどちらも複数あるので自力でデコードする場合にはご注意を。といってHEXなのでそれほど難しいフォーマットではないです。V1系/V2系で共用できるあたりの説明は、micro:bit developer communityの以下のページにあります。

.HEX file format

ま、この共用できるHEXファイルに全面的に頼り切れば、一度生成したHEXファイルは、V1系のmicro:bitに書きこもうが(手持ちはV1.5)、入手したばかりのV2系に書きこもうが動く筈です。今回はこれで二種類のmicro:bitで比較実験行いました。ただ前にも書いたとおり、Flashに書きこむ度にペアリング情報は失われてしまうので、Bluetoothのペアリング作業をやりなおさないとBluetoothは使えませぬ。

さてV2でRAM容量が8倍になって、やりたかったのは以下のようなブロックをmicro:bitに書きこむことです。

v2FULLBluetooth LE(Low Energy)の「サービス」としてMakeCodeエディタが組み込めるもののうち、UARTサービスを除く他の6個のサービス全てを「全部載せ」したものであります。なお、foreverブロック内ではLEDアレイの左上隅でLチカやり続けます(LEDが点滅していればforeverブロックが実行されていることが分かる=ソフトが動いていることが分かる為。)

以前の投稿で書きましたとおり、MakeCodeはこれのHEXは生成できますが、V1.5のmicro:bitに書きこむと、HEX書き込んだ直後にRAM不足のエラーとなって落ちます。

結論からいうと、V2のmicro:bitにこのコードを書きこんでもエラーは起きません。スマホアプリ側から見るとコネクトできているような感じもします。が、明らかに挙動が変。とりあえずスマホアプリは以前に作った buttonサービスとLEDサービスの2つ対応のものです。

結局、何が不具合の原因なのか知るために、古代から連綿と続く伝統技法「試行錯誤」で調べてみました。以下は中間報告です。

  • temperature serviceについては、動作しているっぽい。V2の温度はV1の温度より環境温度に近い感じがする。
  • magnetometer serviceについては、スマホ側のDroidScript環境のプラグインの問題?あり該当BLEパケットを取り出せていない。
  • accelerometer serviceについては、数分なら動作しているが、長いこと動作させるとヤバイ(V1.5だと、最初からヤバイ。)
  • io pin serviceについては詳しい事調べていないが、どうも他のサービスに相性が悪そうなものがありそう。

それでコンサバなところで、V1.5用に作成済の スイッチ+LEDのスマホアプリに温度を追加したものを作り走らせてみました。MakeCodeのブロックはアイキャッチ画像に掲げたものです。DroidScript(JavaScript)の全文(以前のものをチョイ直し)は末尾に。動作の様子はこんな感じです。

v23wAndroid

一番上に Temp=23と表示されているのが、温度は23℃という追加部分です。温度測定のインターバルの制御は出来ていないのですが、デフォルトでは数十秒か数分かに1回くらい改定されている感じです。
しかしね、ちょっとショックだったのが、この「サービス3種盛」のコード、V2だけでなく、V1.5に書きこんでも動作OKでした。ぜんぜんV2のRAM容量拡大、効いてないところでした。とほほ。

結局、V1.5、V2の両方で何度もFlash書き換えちゃ、ペアリング作業をやり直していたので、ペアリングには「習熟」したですが。

ブロックを積みながら(12) EddystoneでBLEビーコン、スマホアプリ作成第1歩 へ戻る

ブロックを積みながら(14) micro:bit V2、BLEで出力スピーカ切り替え へ進む

DroidScript(JavaScript)による改定版スマホアプリ(micro:bit V2, V1.5共用)
app.LoadPlugin("MicroBit");

var btnArray = [];

function OnStart()
{
    lay = app.CreateLayout( "linear", "Vertical" );
    txtTemp = app.CreateText("Temp = ...", 1.0, 0.07, "Bottom" );
    lay.AddChild(txtTemp);	
    txtButtonA = app.CreateText("Button A = ...", 1.0, 0.07, "Bottom" );
    lay.AddChild(txtButtonA);
    txtButtonB = app.CreateText("Button B = ...", 1.0, 0.07, "Bottom" );
    lay.AddChild(txtButtonB);
    txt0 = app.CreateText("Send String to LED:", 1.0, 0.1, "Bottom" );
    lay.AddChild(txt0);
    lay0 = app.CreateLayout( "linear", "Horizontal, FillXY" );
    edt = app.CreateTextEdit("", 0.5, 0.07 )
    edt.SetTextSize( 16 );
    lay0.AddChild( edt );
    btnSend = app.CreateButton( "Send", 0.25, 0.07 );
    btnSend.SetOnTouch( btnSend_OnTouch );
    lay0.AddChild( btnSend );
    lay.AddChild(lay0);
    lay.AddChild(ledButtonLayout());
    btnMatrix = app.CreateButton( "Matrix", 1.0, 0.07 );
    btnMatrix.SetOnTouch( btnMatrix_OnTouch );
    lay.AddChild(btnMatrix);
    app.AddLayout( lay );

    microbit = app.CreateMicroBit();
    microbit.SetOnConnect( OnConnect );
    microbit.SetOnButton( OnButton );
    microbit.SetOnTemp( OnTemp );
    microbit.Scan();
}


function btnSend_OnTouch()
{
    var txt = edt.GetText()
    microbit.ScrollText(txt);
}

function ledButtonLayout()
{
    layLB = app.CreateLayout( "linear", "Vertical" );
    for (let yidx = 0; yidx < 5; yidx++) {
        layLB0 = app.CreateLayout( "linear", "Horizontal");
        for (let xidx =0; xidx < 5; xidx++) {
            btnArray[yidx*5 + xidx] = app.CreateButton( "0", 0.15, 0.07 );
            btnArray[yidx*5 + xidx].SetStyle("Black");
            btnArray[yidx*5 + xidx].SetOnTouch( toggleColor );
            layLB0.AddChild(btnArray[yidx*5 + xidx]);
        }
        layLB.AddChild(layLB0);
    }
    layLB.SetPadding( 0.05, 0.05, 0.05, 0.05);
    return layLB;
}

function toggleColor()
{
    if (this.GetText() == "0") {
        this.SetStyle("#22aa22");
        this.SetText("1");
    } else {
        this.SetStyle("Black");
        this.SetText("0");    
    }
}
    
function btnMatrix_OnTouch()
{
    var workArray = [];
    for (let idx = 0; idx < 25; idx++) {
        if (btnArray[idx].GetText() == "0") {
            workArray[idx] = 0
        } else {
            workArray[idx] = 1
        }
    }
    microbit.SetLEDs(workArray);
}

function OnConnect()
{
    app.ShowPopup("Connected!");
}

function OnButton( name, stat )
{
    var status;
    if (stat == "1") {
        status = "ON";
    } else {
        status = "OFF";
    }
    if (name == "A") {
        txtButtonA.SetText( "Button A = " + status );
    } else {
        txtButtonB.SetText( "Button B = " + status );
    }
}

function OnTemp( x )
{
    txtTemp.SetText("Temp = " + x);
}