なんだかんだでやっぱり必要になった
過去にDFUのことを調べていたとき、最初に見つけたのがUSB経由のDFUでした。BLE経由のDFUを探していたので必要ないなと思いつつも、一度くらいは試しておいて損はないと思って検証したことがあります。
過去に実際に検証したUSB DFU
その時の検証結果がこちらの記事です。
今も動くのかどうか分からないです。というか、動かそうと思って読んだのですがどうすればいいのか全く分かりませんでした(笑)。
VSCodeベースになって以来、全然コマンドプロンプト触らないので当時の記事を見返してみてもさっぱり分かりません。改めて読んでみるといたるところを端折っていて、マジメに書いておかないとこういう時に困るんだなーというのを身をもって味わいました(笑)。
言い訳をするとUSB DFUは本当に使うつもりがなかったもので…
サンプルプロジェクトがある
いつからあるのかまでは把握していませんがUSB DFUに関してはSDKにサンプルプロジェクトがあります。ということでさっそくこのサンプルプロジェクトを実行していきたいと思います。プロジェクト名はdfuです。
なんか以前と全く違う気が…
サンプルプロジェクトを立ち上げてみてまず最初に思ったのは、なんだか以前に実装したものとは全く違うということでした。VSCodeベースになっているし全然違うものになっていてもそんなに不思議じゃないかな…とは思いつつ、どこから手を付けてよいのか全く分かりません。とりあえずREADME.rstを読んでみます。
全てを理解したあとであれば何が書いてあるのかが手に取るように理解できるのですが、全く理解度がない中でこのREADME.rstを読んで「なるほど、そういうことか!」と理解できる人ってどれくらいいるんでしょうね…少なくとも僕は全然理解できませんでした。
老化ですね(笑)
とりあえずコンパイルしてみる
よく分からないのでとりあえずコンパイルしてみます。普通にコンパイルできました、って当たり前ですよね(笑)。ちなみにREADME.rstの最初のほうに出てくるCONFIG_MCUBOOT_SIGNATURE_KEY_FILEについてはBLE版DFUと同様にそのままprj.confに記述しても無効です。詳細についてはBLE DFUの記述を参照してください。
Bootloaderはどうやって立ち上げるの?
nRF SDKにおけるUSB DFUはBootloaderモードに入ることで実施していました。その思い込みもあると思うのですが、まずここで躓きます。はて、どうやってBootloaderモードに入るのだろう?しかしREADME.rstを読んでみてもソースコードも眺めてみてもそれっぽい記述はどこにも見当たりません。nRF SDK時代にあった起動時にボタンを押しているとBootloaderが立ち上がるみたいなKconfigも見つかりません。
結論を言うとBootloaderモードというのはありません。
dfu-utilってなんだ…?
もう一つREADME.rstに謎の記述が現れます。linuxのdfu-utilがなんだかんだと書かれています。はて、これはいったいなんなのだろうか?とりあえずNCSのフォルダ内を漁ってみますがそれらしいものは見つからなかったのでWEB検索してみたところ…なにか引っかかりました。
ん…?本当にこれのことなのだろうか?と半信半疑になりながらもWindows用の実行ファイルをダウンロードします。なお、執筆時点での最新バージョンは0.11です。
なおも半信半疑のままとりあえず動かしてみると…
はて、何かエラーが出ているような気がするんだけど…なんだこりゃ?
このあたりはDevZoneでやり取りして解決しました
デバイスドライバーのインストール
コンパイルしたサンプルプロジェクトをフラッシュに書き込むとWindowsデバイスマネージャにドライバーのないデバイスが現れます。
これが先ほどのエラーっぽいメッセージと関係あるのですが、要するにデバイスドライバーがなくて正常に動作していないことによるエラーのようです。いや、でもデバイスドライバーってどこにあるのさ!
結論としては汎用のUSBドライバーをインストールすればよいみたいです。
ドライバーに互換性がないとか警告が出ますが無視します。
これでビックリマークが消えました。
再びコマンドプロンプトからdfu-utilコマンドを実行してみると…
お、ちゃんと認識しているようです。
別プロジェクトの作成
README.rstに記載されているようにDFUを実際に実行するにあたっては別のプロジェクトが必要になります。ここではhello_worldをベースにDFUが実行できる形にしたものを作成します。ちなみにREADME.rstに書かれているようにCONFIG_BOOTLOADER_MCUBOOTを含む最小限の変更でDFUをするとその次のDFUは実行できなくなります(笑)。
USBを有効にするKconfigとソースコードがないためです。
CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_FLASH=y
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DFU_CLASS=y
CONFIG_USB_DFU_ENABLE_UPLOAD=y
CONFIG_IMG_MANAGER=y
DFU関連のKconfigを入れないとDFU用のapp_update.binを生成してくれません。
いざアップデート…?
これでイケる!と思ったら…
More than one DFU capable USB device found!ってなんですか?!さっきデバイス一つしかなかったと思うんですけど…?と不思議に思いながらdfu-util --listと打ち込んでみると…
ふぁーーー!なんで増えてるの???確信が持てませんがおそらくSLOT 0とSLOT 1の2つを示しているのではないかと思います。長くなるので省略しますがSLOT 0には書き込みができません。
ということでSLOT 1に書き込みます。
お、ちゃんと書き込みできたようです。リセットしてみると…
ちゃんとHello Worldプロジェクトに書き換わっています。よっしゃー!
と思ったのも束の間…
何気なくもう一度リセットしてみたんですよね。そしたら…
えっ?どういうこと?元に戻った?表示されている情報をよく見てみるとrevertという表示もあります。何度やってみても書き込んだ直後のみ新しいファームウェアに書き換わるものの、2回目のリセットで最初のファームウェアに戻されます。なんだこれ…?
追加のKconfigが必要
DFUのサンプルアプリケーションにはよく分からないoverlayファイルが1個あります。
任意追加のオプションのようですが、中身を見てみると…
CONFIG_USB_DFU_REBOOT=y
CONFIG_USB_DFU_PERMANENT_DOWNLOAD=y
調べてみたところ、どうもこれがファームウェアを元に戻さないようにする追加のKconfigのようです。README.rstを読んでみると同様のことが書いてあるのですが、何も知らない状態で読んでみても何のことかさっぱり分からんっつーの!(笑)
先ほどのOverlayファイルを追加して再びコンパイルします。
先ほどまでswap typeのところにtestと表示されていたものがpermに変わっています。もう一度リセットしてみると…
Hello Worldのままです!よっしゃー!
Secure DFU
USB DFUではまだ試しておりません。実は検証するのって意外とめんどくさいんですよ、ええ…。
README.rstではRSA-2048の記載がありますが、実際に使えるのはBLE DFUと同様にECDSA-256です。
総評(という名のAppendix)
ちなみに今回のDFUに関しては全然分からなかったし情報も見つからなかったのでDevZoneでやり取りしました。いや、DevZoneすごいね!
英語でのやり取りもDeepLのおかげで全然苦にならなくなってきました。もちろん丸ごとコピーではなくて少し書き直したりはするのですが、自分で最初から最後まで英文を考える必要がなくなったのでとても楽ちんです(笑)。
ちなみにここ読んでと教えてもらったNordicのホームページはこちら
でも、これ古い気がするんですよね…だって、途中でzephyr.signed.binっていうファイルが出てくるんですが、そんなものは生成されませんし…。