NanoVNA の USB のコミュニケーション方法が USB-CDC で、プロトコル自体は簡単そうだ、というのを前に書きました。なぜそんなことを調べていたかといえばブラウザでUIを作りたかったからなので、作りました。

機能

  • デバイスの現在のデータの読みこみとグラフ化(スミスチャート・周波数応答)
  • 複数のトレースタイプ (clear write / freeze / minhold / maxhold / videoavg / poweravg)
    • freeze が値の比較に便利だと思う。これが欲しくてトレースタイプを実装してます。他のはオマケ
  • ウィザード形式のキャリブレーション
  • デバイス画面のキャプチャ
  • デバイスバージョンの表示 (比較的新しいファームでなければ version コマンドがありません)
  • TDR (Time Domain Reflectometry)
  • s1p s2p 出力。ただし s2p は S22 = S11, S12 = S21 として出力する。

実装

ほとんどの機能は JavaScript で直接実装しています。TypeScript も使っていません。USB Device との通信は WebUSB で、できるだけポーリングを正確にしたいため Worker 内で行っています。このあたりは HackRF One を WebUSB から操作してスペアナを作るのと同じような手順です。

グラフは chart.js をそのまま使っているので工夫したところはありません。

現状では TDR 測定のところでだけ Rust で書いた実装を wasm にしたものを呼んでいます (TDR は RL をただ ifft しているだけです)。パフォーマンスが必要なわけではないのですが、複素数の計算を JS でやるのがとにかく面倒かつ可読性を損うので、Rust 資産を流用しという魂胆です。

本当は、Rust での処理は生dump データから、デバイスでやっている計算すべてをホスト側でやるのも見越してやりはじめましたが、一通りスキャンするのにかえって時間がかかりそうなのでやるのをやめました。ヒルベルト変換は fft/ifft でできるし、すぐ実装はできそうではあります。

備考:WebUSB と USB-CDC の将来は不安

WebUSB はそもそも既存のよくあるUSBデバイスに対してアクセス権限を与えるようなコンセプトのものではなく、USB-CDC も同様にスコープに入っていません。本来はSerial APIという提案仕様があって、こちらでカバーされるはずです。だけれど現状では実装されているブラウザが存在しません。

ということでやはりWebUSB でやるしかないわけですが、OS間で取り扱いが違うので意外と面倒くさいことがわかりました。

  • Windows では CDC 用のドライバがインターフェイスを握ってしまう
    • ドライバを libusb 用のものに置き換えれば使える
  • Ubuntu では cdc_acm ドライバがインターフェイスを握ってしまう
    • udev ルールで bind 直後に即 unbind することができる。

ドライバを入れ替えると普通のシリアルポートとしてOSには(当然だけど)認識されなくなるので、必要に応じて再び入れ替えたりする必要があります。

ここで一つ問題があって、現行の NanoVNA は USB の vid/pid を STM32 の CDC デバイスのもの(?)を流用しているため、上記のようなドライバ置き換えが他の STM32 デバイスに影響を及ぼすことがあります。vid/pid の関するイシューはあるのでそのうちなんとかなるかもしれませんが現状ではこの通りです。

なお macOS は実際のデータ転送に使うインターフェイスは、実際にポートがopenされるまで排他的に確保しないようで、WebUSB からも自由にアクセスできます。逆に WebUSB で握っている間にシリアルポートを別途開こうとすると、そのタイミングで resource busy が出ます。

現行の Android では特に何もせず、OTG コネクタさえ使えば接続することができました。ただ、中華NanoVNAはコネクタにType-Cを採用はしているものの、CC に何も接続されていないため、Type-C - Type-C ケーブルを使うとデバイスを認識しません。Type-A OTG 変換ケーブルなどを経由する必要があります。

とりあえず何が言いたいかというと、今のところ WebUSB で USB-CDC デバイスをなんとか動かす方法は存在しているけど、今後はどうなるかわからないということです。WebUSB 自体も (使われなければ) 消滅する予感のする仕様と感じています。少なくとも今の仕様 (パーミッションダイアログが危険性の割に雑) のまま広く使われることもないだろうと思います。

  1. トップ
  2. tech
  3. NanoVNA を WebUSB を使ってブラウザから見る
  1. トップ
  2. nanovna
  3. NanoVNA を WebUSB を使ってブラウザから見る

C0 → CAL0 の設定を読んでいる状態。
    c0 のように小文字の場合はエラー値の補完をしている状態
    (recall してから周波数範囲を変えた場合。厳密には uncal )
D → directivity エラー修正
R → refrection tracking エラー修正
S → source match エラー修正
T → transmission tracking エラー修正
X → isolation (crosstalk) エラー修正

それぞれの意味はエンハンストレスポンス校正あたりで検索する (自分はよく理解してない)

なお cal を done したときに、終わった calibruation menu のハイライトが一部消えるのは正常 (上記エラー情報を計算し終えると消える仕様)

  1. トップ
  2. tech
  3. NanoVNA 左側の文字の意味
  1. トップ
  2. nanovna
  3. NanoVNA 左側の文字の意味

ポインタ配列の const が理解できなかったのでメモ

検証コード

const char* const foo[] = {"foo","bar","baz"};

extern void __print(const char* buf);
void main(void) {
	char* str;
	__print(foo[0]);
}

これの foo のついている2つのconstを消したりつけたりする。__print は最適化で消されないように extern してるだけで特に意味はない。

arm-none-eabi-gcc -c c.c -o a.o && arm-none-eabi-objdump -t a.o

このようにして symbol table を見て、どのセクションに配置されるかを確認する。

char* foo[]

...
00000000 g     O .data  0000000c foo
00000000 g     F .text  0000002c main
...

当然 .data に配置される。

const char* const foo[]

...
0000000c g     O .rodata        0000000c foo
00000000 g     F .text  00000028 main
...

当然 .rodata に配置される。

const char* foo[]

...
00000000 g     O .data  0000000c foo
00000000 g     F .text  0000002c main
...

.data に配置される。

これがいまいちよくわからない。ここにconstをつけても以下はコンパイルエラーにならない。何が const になっているのだろう?「ポインタの配列 foo」そのもの?

foo[0] = "piyo";

しかし以下のように「ポインタの配列 foo」そのものを更新しようとしてもエラーになるので、そもそも「ポインタの配列 foo」そのものを更新しようがない気がする。

	char* bar[] = {"xxx"};
	foo = bar; //=>  error: assignment to expression with array type

char* const foo[]

0000000c g     O .rodata        0000000c foo
00000000 g     F .text  00000028 main

.rodata に配置される。

この場合、foo[0] への代入はコンパイルエラーになる。「ポインタの配列」の「ポインタ」が const になっている?

「ポインタ配列」の場合、上記のように「ポインタの配列 foo」そのものを更新しようがないので、.rodata で良いのだろうか?

foo[0] = "piyo"; //=> error: assignment of read-only location 'foo[0]'

char* const foo と const char* const foo は全く同じバイナリが吐かれる。ポインタ配列の最初の const は無意味なのだろうか?

  1. トップ
  2. tech
  3. C言語のポインタ配列の const の効果