nRF52840のDFUでSlot1がpermanentになり詰んだ話 - ダウングレードによるデバイスロック問題

この記事はLLM(GitHub Copilot)によって作成されました。

nRF Connect SDK 2.9で開発したnRF52840のファームウェアで、MCUboot/MCUmgrを使ったDFU(Device Firmware Update)中に、デバイスが完全にロックされてそれ以上DFUできなくなるという深刻なバグに遭遇しました。この問題は既にオープンソースコミュニティでも報告されていますが、ダウングレード特有のケースは明示的に議論されていないため、本記事で詳細を共有します。

発生した問題

症状: デバイスの完全なロック

バージョンが小さいファームウェアをDFUすると、デバイスが完全にロックされ、それ以上DFUできなくなるという問題が発生しました。

具体的な流れ:

1. Primary Slot: v1.0.2.2 (実行中)
2. DFU実行: v1.0.1.1 をアップロード
3. 再起動
4. MCUbootがバージョンチェック: 1.0.2.2 > 1.0.1.1 → スワップ拒否
5. Primary Slot: v1.0.2.2 のまま起動
6. Secondary Slot: v1.0.1.1 が pending 状態で残る
7. 次のDFUを試みる
8. MCUmgr: "There is no free slot to place the image" エラー
9. デッドロック状態 → DFU不可能

再現条件

以下の3つの条件が揃うと必ず発生します:

  1. ダウングレード防止が有効

    CONFIG_MCUMGR_GRP_IMG_VERSION_CMP_USE_BUILD_NUMBER=y
    
  2. バージョンが小さいイメージをDFU

    • Primary: 1.0.2.2
    • DFU: 1.0.1.1 (ダウングレード)
  3. PERMANENT modeで書き込み (nRF Connect appのデフォルト)

M1 Macで、Pythonのdlopenでエラーが出た時の対処

Google apiをpythonで使おうとして、エラーが出ました。M1 Macで、Pythonを使っていると、arm64eアーキテクチャのpythonで、x86_64アーキテクチャのダイナミックライブラリを読みこうもうとして、dlopen()でエラーが出ることがあります。インストールする側でバイナリを使わずビルドすれば、ビルドに数分ほど時間はかかりますが、これを解決できました。

https://stackoverflow.com/questions/69788752/on-apple-m1-grpc-google-api-import-error

pip install --no-binary :all: grpcio --ignore-installed
pip install --no-binary :all: grpcio-tools --ignore-installed

x86_64アーキテクチャで揃えるのはめんどくさすぎる

pipでインストールしても、パッケージ提供元からarm64eのアーキテクチャのライブラリがビルドされていないと、どうにもならないようです。対処方法として、

arch -x86_64 /bin/zsh

で、アーキテクチャを指定してから、pythonをインストールして、すべてx86_64アーキテクチャにするのがありますが、めんどくさすぎます。

WatchOS8でバックグラウンドリフレッシュでBLE

WatchOS8でバックグラウンドリフレッシュでBLE

WWDC2021 Connect Bluetooth devices to Apple Watch https://developer.apple.com/videos/play/wwdc2021/10005/

WatchOS8で、バックグラウンド アプリ リフレッシュで、BLEが限定的ですが、利用可能になりました。

仕組みとしては、アプリ側からペリフェラルの接続を出します。バックグラウンドでアプリがリフレッシュされている期間に、たまたまペリフェラルのアドバタイジングパケットが来れば、CoreBluetoothが、ペリフェラルと接続して、アプリとの通信を確立させます。

制限として、バックグラウンドで接続できるのは、その前にアプリがフォアグラウンドで、接続をした、あるものはペアリングもした、ペリフェラルのみです。新規のペリフェラルの発見は、バックグラウンドではできません。

アプリがリフレッシュ期間を終えて、ペリフェラルとの接続がまだ閉じていない場合は、CoreBluetoothが自動的に接続を切ります。次の、アプリリフレッシュタイミングが開始した時に、アプリはCoreBluetoothからdidDisconnectを受け取ります。アプリのリフレッシュをまたいで、切断イベントが通知されることに、注意します。

接続には、アプリがバックグラウンドにある間に、アドバタイジングパケットが来なければなりません。アプリのリフレッシュタイミングは指定ができないので、ペリフェラルは適度な頻度でアドバタイジングをし続けるしかないのですが、プレゼン中の説明では、感覚的な目安としては?2秒くらい?の間隔が1つの目安みたい?です。

AWSのAmplifyが、単なるウェブサイト公開にも便利だった話

もうタイトルで全てなのですが。

AWSには、ウェブ・アプリおよびモバイル・アプリの開発と公開とを最速かつ簡単にするフレームワークとして、https://aws.amazon.com/jp/amplify/ が提供されています。この中身は、AWSが提供するいくつものサービスを、開発向けに機能として使えるように束ねたものと言えます。

単なるウェブサイトの公開にかかる手間

amplifyは、単なるウェブサイトの公開に使っても便利でした。 AWSで、ウェブサイトを公開する場合:

  • まずS3バケットを作り、それをCloudFrontにつなげて公開して、
  • カスタム・ドメインで公開したい場合はRoute53でドメインを管理して、そこからCNAMEでCloudFrontにつなげて、
  • さらにhttpsもサポートしたいならばAWSのSSL証明書発行をつける、 という手順を踏みます。

Amplifyの手動デプロイでウェブサイト公開

Amplifyのコンソールだと、まず空のプロジェクトを作ります。この時点で、Amplifyが内部で、S3のバケット作成とCloudFrontの設定が完了した状態にしてくれます。デプロイは、手動デプロイに設定します。こうしておくと、コンソールで、index.htmlを含むファイル一式をZIPアーカイブにしたものをドロップすれば、AWS側で解凍してウェブとして公開してくれます。ドメイン名、サブドメイン、SSL証明書の設定も、コンソールから設定ができます。

Amplifyでかかる料金

Amplifyの課金は、ウェブアプリのビルド時間と、コンテンツのストレージ、そしてインターネットへの転送料金分です。ビルドは、4 vCPUで7GBメモリのDockerイメージで走っていました。おそらくデプロイの計算量やコンテンツの保持は無視できるほど小さいものでしょう。残るのはインターネットの転送料ですが、これは、地域の区別なく1GBあたり0.15ドルとあります。CloudFrontのインターネット外部転送量が、米国だと0.7ドルくらい、インドだと0.17ドルくらいとありますから、Amplifyの転送量は、CloudFrontの最も高い料金より少し下くらいに設定されていると思っておけばよさそうです。

もちろんウェブ・アプリにも便利

Amplifyは、もちろんウェブアプリにも便利です。アプリというと商業的開発のイメージが浮かぶかもしれませんが、意外と使っているものです。

例えば、私のブログサイトは、hexoというNode.jsを使う静的ウェブ生成ツールを使っています。また仕事で、簡単なデモンストレーションのためのウェブ・サイトを作る必要があるときに、私はウェブでそれなりの見た目の画面が作れないのですが、IonicというNode.jsを使いウェブ・アプリケーションの開発フレームワークを使い、そのほぼテンプレートなプロジェクトにちょっとテキストや画像を入れて、それらしい画面を作っています。

私が作るブログもデモサイトも、Ionicなどを使っていてもバックエンドを使わない単なる静的ウェブ・コンテンツでしかないので、Amplifyの手動デプロイでも十分です。ですが、わかりきった作業をするのも手間なので、ソースのレポジトリからデプロイする設定にしておくのもいいかもしれません。ローカルでビルドして、S3にrsyncしてもいいのかもしれませんけど。

Amplify本来の使い方なので、ドキュメントを見ながらやれば、できるでしょう。気をつけるのは、Amplifyの最初の設定で、どのフォルダにindex.htmlをはじめとするファイル一式が生成されるフォルダを設定する"dist"の設定が正しいことを確認すること、何か特別なリソースファイルを使う場合は、Amplifyのリダイレクト設定で、jpgやらpngやらの拡張子がたくさん並んでいる設定のところに、その特別なリソースファイルの拡張子も追加しておくこと、くらいだと思います。

日本の接触確認のキー情報をモニタしてみる

日本の接触確認のキー情報をモニタしてみようと思います。

このキー情報というのは、テンポラリキーです。Apple/Googleが提供する曝露通知の仕組みは、暗号化された識別子を送信し、お互いに記録するものです。陽性判定された方がアプリケーションにそれを登録すると、アプリケーションは、その識別子を生成する元になっているテンポラリキーのリストを、端末に記録されている過去14日分を、サーバーに送ります。それぞれのアプリケーションは、そのテンポラリキーと端末に保存された識別子を照合して、接触していたかの有無を判定します。

テンポラリキーは、各人の端末で1日1つ生成されます。ですから、もしもアプリケーションを使用開始してから14日以上が経過した方が、陽性判定でそのデータを送れば、14個のテンポラリキーがサーバに送られます。2日しか使っていなければ、多分キーは2つだけでしょう。

毎日深夜に、その日に新たに生成されたキーの数を数えれば、多分それは陽性判定の新規登録者数です。プライバシー保護のために、ダミーデータが混じっているかもしれませんが、大まかな傾向としては間違いではないでしょう。

その日に登録されたキーの数をカウントするスクリプトを作って見ました。処理の詳細は、Gistのコードをみてください。Python3で書いています。macOSのターミナルで動作を確認しています。

ソースコード : https://gist.github.com/reinforce-lab/7810b3edc4aee5a72c41c928d4d89076

使い方は、まずコードをローカルに展開します。zipで落とすだけでいいのではないでしょうか。そして次のコマンドで、キー情報が見られます。

% pip3 install protobuf % pip3 install requests % python3 covid19radar_detail.py

(Jupyterとかでなんか動かなかったら、 % pip install –upgrade google-api-python-client で動くかも?) (Windowsとかだと、 % pip3 install requests もいるかも?)

これで、実行した日付に登録されたキーの総数を表示します。夜に定時実行させておけばいいと思います。 多分、7月16日の登録者数は8人くらいなのでしょう。