BLEの最大データサイズ?

今さらですが、BLEの最大データサイズって (BLE4.2以降のデータ長拡張は別として) 何バイトでしょう? 27バイト? 23バイト? 22バイト? 20バイト?

資料によってまちまちで混乱しませんか? 中には「20バイト程度」とかボカして書かれてたり。これ、図解すると下図のようになります。

f:id:licheng:20200609094836p:plain

27バイトというのはLLのペイロードの最大サイズ、23バイトというのはL2CAPのペイロードの最大サイズ、22バイトや20バイトというのはATTのペイロードの最大サイズです。

BLEもEthernetとかと同様に何段にもプロトコルが積み重なってるので、上にいくほどヘッダが削ぎ落されてペイロードが小さくなっていきます。Ethernetだと元が1500バイト以上あるのでそこまで気になりませんが、BLEは元が小さいのですごく目減りする感じがします。

結論としてキャラクタリスティックの最大データサイズはReadでは22バイト、Write, Notify, Indicateでは20バイトとなります。が、Read専用の場合だけ22バイトというのもおなしな話なので一律最大20バイトと考えたほうが無難に思います。

しらんけど。

5月のまとめ

進捗

  • SOEMのNucleo-F767ZI対応
  • SOEMのM5Stack対応
  • ミニ四駆ラジコンのRumiCar化

動画公開


所感

先月に続き停滞気味で体調も崩しがちだったが、ながらく苦戦したSOEMのNucleo対応にようやく成功し、少し勢いが戻ってきた感じ。新たにRumiCarというお題にも取り組みはじめた。来月はさらに勢いを取り戻したい。

Mbed OS 5を静的ライブラリとしてビルドする

【2020/05/21 追記】
本記事の手順で作成したMbed OS 5の静的ライブラリを使用すると正常に動作しないケースがありました。発生条件や原因は調査中です。

やりたいこと

Mbed OS 5をあらかじめ静的ライブラリとしてビルドしておく。

背景

Mbed OS 5のソースコードは膨大な量で、非力なPCではフルビルドに数十分もかかります。またインクリメンタルビルドですら更新チェックにかかる時間が煩わしいです。ユーザープログラムの開発者がOSのソースコードを変更することはふつう無いので、これは時間の無駄です。

そこで、Mbed OS 5を別プロジェクトであらかじめ静的ライブラリとしてビルドしておき、ユーザープログラムのプロジェクトではビルド済みの静的ライブラリを利用することでビルド時間を短縮したいと思いました。

開発環境

ここでは例として、Nucleoボード(STM32マイコン)をターゲットとし、ローカルビルド環境としてSW4STM32 (Eclipseベース)を使用します。他のEclipseIDEでもだいたい似たようなものだろうと思います。

Mbed CLI ならもっと洗練された方法があるのでしょうか? 今回はそちらは未調査です。

Mbed OS 5用プロジェクトの作成

  • Mbedのオンラインコンパイラでプロジェクトを作成します。ここでは「プラットフォーム」を「NUCLEO-F767ZI」、「テンプレート」を「mbed OS Blinky LED HelloWorld」、「プログラム名」を「mbed-os」とします。
  • 「プログラムのエクスポート」でこのプロジェクトをzipでダウンロードします。ここでは「Export Target」を「NUCLEO-F767ZI」、「Export Toolchain」を「SW4STM32」とします。

f:id:licheng:20200516161254p:plain

  • SW4STM32を起動し、[File] > [Import] > [Existing Projects into Workspace] でzipファイルを選択してプロジェクトをインポートします。
  • main.cppは不要なので削除します。 (エクスプローラで削除した場合はSW4STM32でF5キーを押してリフレッシュします。)
  • [Project] > [Properties] > [C/C++ Build] > [Build Artifact] で [Artifact Type] を Static Library に変更し、[Artifact name] を ${ProjName} に、[Artifact Extension] を a に、[Output prefix] を lib にします。

f:id:licheng:20200516230806p:plain:w640

  • [Project] > [Properties] > [C/C++ Build] > [Build Steps] で [Post-build steps] を空欄にします。

f:id:licheng:20200516174206p:plain:w640

Mbed OS 5の静的ライブラリをビルド

  • [Project] > [Build Project] でプロジェクトをビルドします。
  • MBED_COMPILER_BARRIER の行で「'asm' undeclared」というエラーが発生する場合はこちらを参照。
  • ビルドが成功するとプロジェクトフォルダの下の Debug または Release フォルダに libmbed-os.a というファイルができます。
  • これがMbed OS 5の静的ライブラリファイルですので取っておきます。

ユーザープログラムのプロジェクトを作成

  • Mbedのオンラインコンパイラでプロジェクトを作成し、zipファイルにエクスポートしてSW4STM32にインポートします。手順は上記「Mbed OS 5用プロジェクトの作成」の場合と同様です。
  • プロジェクトフォルダの下の mbed-os フォルダの下に、さきほどビルドした libmbed-os.a をコピーします。
  • プロジェクトフォルダの下の mbed-os フォルダの下にある、拡張子が c または cpp のファイルを全て削除します。Windosの場合は下記のようなバッチをプロジェクトフォルダの下で実行すると削除できます。
@echo off
for /R mbed-os %%i in (*.c) do del %%i
for /R mbed-os %%i in (*.cpp) do del %%i
  • Linuxの場合はプロジェクトフォルダの下で下記コマンドを実行すれば削除できます。たぶんMacでも同様。
find mbed-os -type f -name "*.c" -delete
find mbed-os -type f -name "*.cpp" -delete
  • SW4STM32でF5キーを押してリフレッシュします。
  • [Project] > [Properties] > [C/C++ General] > [Paths and Symbols] > [Library Paths] に mbed-os を追加します。 (これは libmbed-os.a を置いたフォルダの指定です。)

f:id:licheng:20200516221148p:plain:w640

  • [Project] > [Properties] > [C/C++ General] > [Paths and Symbols] > [Libraries] に mbed-os を追加します。(これはライブラリ名の指定です。頭に「lib」を付けないことと、拡張子「.a」を付けないことに注意してください。)

f:id:licheng:20200516221205p:plain:w640

ユーザープログラムをビルド

  • [Project] > [Build Project] でプロジェクトをビルドします。
  • かなり短い時間でビルドが完了するようになります。
  • 「undefined reference to `__wrap__free_r'」等のエラーが発生する場合はこちらを参照。
  • さらにビルド時間を短縮するためにMakefile生成を抑制するにはこちらを参照。
  • デバッグ実行時に「OpenOCD Binary not found」と言われたらこちらを参照。

以上で非力なPCでもMbed OS 5の開発できそうな気がしてきました。

__wrap__free_rが無いと言われたら

MbedのプロジェクトをGCC環境にエクスポートしてビルドすると、リンクの段階で下記のようなエラーが発生する場合があります。(どういう場合に発生するのか不明。)

undefined reference to `__wrap__free_r'
undefined reference to `__wrap__malloc_r'
undefined reference to `__wrap__calloc_r'
undefined reference to `__wrap__realloc_r'

この場合、リンカのオプションから対応する下記のものを削除すればエラーが解消します。

-Wl,--wrap=_free_r
-Wl,--wrap=_malloc_r
-Wl,--wrap=_calloc_r
-Wl,--wrap=_realloc_r

Eclipse系のIDE、例えばSW4STM32の場合、[Project] > [Properties] > [C/C++ Build] > [Settings] > [Tool Settings] > [MCU G++ Linker] > [Miscellaneous] の [Linker flags]で設定できる。

f:id:licheng:20200516204832p:plain

WindowsのIPアドレス設定画面どこ行った?

Windows10って、「コントロールパネル」と「設定」とが朝廷と幕府みたいに併存してるの、いいかげんなんとかならんのかな?

IPアドレスの設定画面の出しかたなど、Windows XP以来ころころ変更されてる気がする。Windows10 (1909)での出し方を以下にメモする。

たぶんいちばん速い出しかた

  1. Win+Xキー押す → 「ネットワーク接続」 (またはWキー押す)
  2. アダプターのオプションを変更する」(地球とモニタのアイコン)
  3. ネットワークアダプタを選んでプロパティを開く

他の出し方(1)

  1. スタートを右クリックして「設定」 (または左クリックして歯車のアイコン)
  2. ネットワークとインターネット」(地球のアイコン)
  3. アダプターのオプションを変更する」(地球とモニタのアイコン)
  4. ネットワークアダプタを選んでプロパティを開く

他の出し方(2)

  1. 「ここに入力して検索」に「コントロールパネル」と入力して開く
    またはスタートメニューから「Windowsシステムツール」→「コントロールパネル
  2. 大きいアイコンの表示で「ネットワークと共有センター
    またはカテゴリの表示で「ネットワークとインターネット」→「ネットワークと共有センター
  3. 「アダプタの設定の変更」(左上にある)
  4. ネットワークアダプタを選んでプロパティを開く

設定でもコントロールパネルでもけっきょく同じところに行くんじゃん…

PSoC CreatorでPDLが無いと言われたら

PSoC Creatorをアップデートした場合(?)に、下記のようなエラーが出ることがあります。

f:id:licheng:20200511100231p:plain

PDLとは「Peripheral Driver Library」で、PDL v2はFM0+やFM4に、PDL v3はPSoC6に対応しています。(PSoC4やPSoC5はそんなライブラリ要らないってこと?)

PDLは C:\Program Files (x86)\Cypress\PDL か C:\Users\ユーザ名\Documents\Cypress\PDL にインストールされています。もしもインストールされていなければ こちら からダウンロードしてインストールします。

PSoC Creatorのメニューの「Tools」→「Options」の「Project Management」で、PDLのパスを指定すればエラーは解消されます。

f:id:licheng:20200511103016p:plain

Androidアプリでのファイル読み書き

※ 今さらな内容のメモです。かなり古い内容を含んでいる可能性があります。

Androidアプリで設定データなどを保存するにはSharedPreferencesを用いるのがいちばん簡単である。
しかし、USB接続でデータファイルをPCとやりとりしたい場合もある。その場合、ファイルの読み書きは次のようにおこなう。

ディレクトリ作成

    // ストレージ直下に Hoge というディレクトリが無ければ作成
    String dirPath = Environment.getExternalStorageDirectory().getPath() + "/Hoge/";
    File dir = new File(dirPath);
    if(!dir.exists()){
        dir.mkdir();
    }

書き込み

    // Hoge/Piyo.txt というファイルに書き込み
    filePath = dirPath + "Piyo.txt";
    FileOutputStream fos = new FileOutputStream(filePath);
    OutputStreamWriter osw = new OutputStreamWriter(fos);
    BufferedWriter bw = new BufferedWriter(osw);
    
    bw.write("hogehogepiyopiyo");
    bw.newLine();

    bw.flush();
    bw.close();
    fos.getFD().sync(); // ストレージの同期
    fos.close();

読み出し

    // Hoge/Piyo.txt というファイルから読み出し
    filePath = dirPath + "Piyo.txt";
    FileInputStream fis = new FileInputStream (filePath);
    InputStreamReader isw = new InputStreamReader (fis);
    BufferedReader br = new BufferedReader(isr);

    String line = br.readLine();

    br.close();
    fis.close();