BCM20737SのOTAFU

# はじめに
## この記事について
Broadcom社のBluetooth Smart SiP BCM20737のOTA Firmware Upgradeについて、正確な情報を集めるのに苦労したので簡単なメモ。

## OTAFU: Over-the-Air Firmware Upgradeとは？
ファームウェアを自身のBluetooth Service上で更新する機能です。Bluetoothなので当然無線でファームウェアの書き換えができるという便利な物なのですが、同時にファームウェアが壊れると更新ができなくなるという両刃の剣。

Broadcom社のチップは、SDK付属のサンプルコードをベースにしてWsOtaUpgradeというサービスを組み込めば自作のファームウェアにも簡単にOTAFU機能を取り込めるので便利。サービスごとに独立したコードを書くようなスタイルになると思うので、自分で追加実装したサービスが壊れていたとしても、そちらのサービスさえ叩かなければ多少のバグでは壊れないはず。ただし、サービス登録とディスパッチ部分でヘマをするとその限りではないので注意。

誰でも無線経由でファーム書き換えができると怖いので、Secure OTAFUという実装も用意されている。こちらは鍵を知らないと更新できないような仕組みが実現できる。OTAを有効にしたまま運用したい場合には便利かも。趣味で使ってる分には「敵対するプログラマと同居してる」なんて状況にない限りは気にしなくても良いかと。

# SDK
## 入手までの道のり
[Broadcom社のコミュニティページ](https://community.broadcom.com/community/wiced-smart)にアカウントを作る必要があります。フリーメールだと登録できないのが難点。真面目に記入しないとrejectされる事もあるようなので注意。

アカウント入手後は[Download SDK](https://community.broadcom.com/community/wiced-smart/wiced-smart-documentation)からWICED-Smart-SDK-x.y.z-IDE-Installerみたいな名前で公開されているインストーラをダウンロード。現時点で自分が試したバージョンは2.2.1です。

SDKについてはWindows, OS X, Linux版が公開されているけど、ホスト用のOTAFUツールが付属しているのはWindowsのみ。AndroidやiOS向けのツールも存在するけど、開発に使うには面倒なので覚悟を決める必要あり。

## SDKインストール時の注意点（Windowsの場合）
LaunchAnywhereというインストーラが使われているのですが、名前に騙されてはいけません、どちらかと言うとLaunchSomehowです。Javaが入っていなければJavaがないと言われるのでインストールするまでなのですが、ここで最新の8系列を入れてしまうと「Windows error 2 when trying to start installer」というエラーにハマります（日本語ロケールだと日本語で同じ意味のメッセージになります）。セキュリティを気にする人は入れたくないでしょうけど、覚悟を決めてサポート切れの7系列をインストールします。

SDK自体もEclipseベースなのでJava VMが必要ですが、こちらは8系列でも問題なく動いてますので、インストール後はJava 7を削除するほうが良いでしょう。SDKは32bit版のVMを前提にしているので、例えWindowsが64bitでも32bit版のJDKないしJREがインストールされている必要があります。

Java 7と8を同居させた際、Configure Javaから使うバージョンを切り替えられるように見えるのですが、あくまでもWebブラウザで使うJava VMのバージョンを切り替える機能なので注意。環境変数Pathを書き換えて最初にJava 7のバイナリを見つけるようにした状態でcmd.exeからインストーラを起動するのが確実です。もしかしたらJAVA_HOMEの書き換えも必要かも。

# サンプルコード
## 場所
Documents\WICED\WICED-Smart-SDK-2.2.1\WICED-Smart-SDK\Apps\ota_firmware_upgradeにあります。

## Build
cmd.exe上でWICED-Smart-SDKディレクトリまで移動して

```shell-session
C:...\WICED-Smart-SDK>make ota_firmware_upgrade-BCM920737TAG_Q32 build
```

とすれば、build以下に生成物が吐かれます。.ota.binで終わる名前のファイルがOTAFU用のデータ。

## 書き込み
ota_firmware_upgrade\peerapps\Windows\WsOtaUpgrade\Release\x86\WsOtaUpgrade.exe がホスト用のツール。第一引数に.ota.binファイルを渡して起動すると、単純なダイアログベースのGUIが起動します。このツール、エラーが起きても基本だんまりなので、困ったときはデバッガ上で起動するか、OutputDebugStringを拾うツールを起動しておきましょう。多少はログを吐くので、だいたい止まってる場所はわかります。

安定して動くか不安な時も、とりあえず起動してしまって大丈夫かと思います。プロトコル的にはファームを全部転送したあと、CRC32のチェックに通った場合だけ実際の書き換えが発生します。

# 備考
## ハードウェア互換性
Windowsから書き込みを行う際、Broadcom社のBCM20702ベースのUSBドングルが必要といった情報もあるのですが、これは[Windows 7以前の話](http://community.broadcom.com/thread/1275)です。Windows 8以降では標準のBluetoothApis.dllを使うので、特にハードウェアは選ばないようです。

## プロトコル
ホスト用ツールのディレクトリにReadMe.txtとして簡単な説明があるのですが、微妙に嘘があります。

1. Control Portに1（1バイト）を書き、0が返ってくるのを待つ
2. Control Portに2（1バイト）、ファームウェアサイズ（32bit Little Endian）の合計5バイトを書き、0が返ってくるのを待つ（追記：ただしチップ側では16bitしかサイズを見ない）
3. Dataに20バイト単位でファームウェアの中身を書き込む。応答は不要。最後のパケットは20バイト未満でもパディング等はしない。
4. Control Portに3（1バイト）、CRC32（32bit Little Endian）の合計5バイトを書き、0が返ってくるのを待つ。

CRCはWsOtaDownloader.cppを見れば具体的な計算がわかります。

## Windows以外の書き込みツール
[WICED Smart BCM92073X OTA Firmware Upgrade (2)](https://community.broadcom.com/thread/3093)と[SOTAFU for Android and iOS](https://community.broadcom.com/community/wiced-smart/wiced-smart-forums/blog/2015/05/27/sotafu-for-android-and-ios)というスレッドにプロトコルの説明と、Android/iOS向けのサンプルアプリがソース付きで公開されています。

## Koshian
[BCM20737ベースのkonashi互換モジュール](http://www.m-pression.com/ja/solutions/boards/koshian)で、[Getting Started](http://www.m-pression.com/ja/c/document_library/get_file?uuid=16352244-c1d9-46a9-b0fc-326c02413c39&groupId=10157)によればBroadcom社互換のOTAFU機能が組み込んである、との事なのですが……試した限りでは動いていません。

サンプルと同じUUIDでサービスが公開されているのは確認できました。ただ、中のCharacteristicについてUUIDに微妙な違いがあります。

- Service
 + 9E5D1E47-5C13-43A0-8635-82AD38A1386F
- Control Point Characteristic
 + E3DD50BF-F7A7-4E99-838E-570A086C666B
- Data Characteristic
 + 92E86C7A-D961-4091-B74F-2409E72EFE36
- App Info Characteristic
 + 347F7608-2E2D-47EB-91E9-75D4EDC4DE3B (Broadcom)
 + 347F7608-2E2D-47EB-913B-75D4EDC4DE3B (Koshian)

Control Pointがnotificationとindicatorをサポートしているので、最初の書き込み前にClient Characteristic Configurationでnotificationを選択するのが公式ツールの手順。Koshian相手の時はこの際のデスクリプタ書き込みでエラーが発生して（無言で）異常終了。WindowsでもAndroidでも同等の箇所で落ちているので、なんらかの特殊な手順を組み込んだ派生プロトコルになっているのではないかと推測。

実はKoshian目的でアレコレ試していたので残念。SDKからの書き込みのテストはKoshianではなく、OS X上でPeripheralとして実装したダミーアプリで確認しました。

追記：App InfoのUUIDですが、どうやらサンプルのソースコードにtypoがある模様（コメントに書かれたUUIDとコード中のバイナリ列が違う）。なのでKoshianが間違っているのではなく、サンプルから派生したコードは全部913Bになっているようです。