無料 Wi-Fi なんかでよくある、接続時にログインさせられるやつ。あれの名前は Captive portal というやつらしい。各OSともにこれを検出したときはログインダイアログを表示するような実装になっている。

Captive portal が出る条件は (OSによって違うだろうけど)

  • OS 側が用意するドメインへの http アクセスをリダイレクトすること

のようだ。OS側が用意するドメインとは例えば

  • captive.apple.com (macOS)
  • connectivitycheck.gstatic.com (Android)

みたいなやつ

やることとしては

  1. DNS サーバを立てる。全ての A レコードクエリに対し captive portal の IP アドレスを返すようにする
  2. DHCP の DNS サーバに自分の IP アドレスを指定
  3. captive portal は HTTP サーバを立て、自分以外のホストへのリクエストをすべて自分のホストへリダイレクトする

これで macOS と Android でダイアログが出ることは確認した。

メモ

自力で DNS Server を実装するとOSの違いに気付くことがある

  • macOS は DNS response に QUERY が含まれていなくても (ANSWER だけで) 認識する
  • Android は DNS response にQUERY が含まれていないと認識しない
  1. トップ
  2. tech
  3. Wi-Fi 接続時に OS のログインダイアログを出させる方法 (Captive portal)

トラブルシューティング

DMA ではない HAL_UART_Transmit は動くか試す。動かないなら UART の設定やピンを確認してみたほうが良い。

DMA すると何も動かんとき

generated code がうごかないじゃん…… となったら HAL_DMA_Init を最初にもってくると動くことがある。

とりあえず変更して試すなら適当に編集して試せば良い。が再生成するとき困るので、CubeMX 上でこの順番は変えておくのが良い。Project Manager → Advanced Settings にいくと順番を変更するUIがある。

最初の一回だけ成功するとき

UARTn global interrupt をオンにする。HAL_UART_IRQHandler あたりで送信の後処理とかをしているようで、この割込みが有効でないと最初の DMA 以降は HAL_BUSY となり成功しない。

  1. トップ
  2. tech
  3. STM32 CubeMX で生成した HAL_UART_Transmit_DMA がうまく動かないとき

Aliexpress で LNA 買ってみた。

Specification:
Model: 50K-4G
Optional Type: Bare Board, CNC Shell
Power Supply Voltage: DC9-15V, typical +12V (Typical current value 45mA)
Gain: Typical value 25dB 0.8G
Input Output Impedance: 50Ω
Maximum output power: P1db + 16dBm 0.8G
Input signal: <0dBm (>0dBm input signal has been distortion)
Bandwidth: 50K-4GHZ (different gain in different frequency)
Noise Coefficient: 1.9dB 1.9GH
Bare Board Size: Approx. 6*2.5cm/2.4*1inch

CNC Shell Size: Approx. 7*3.3*1.3cm/2.8*1.3*0.5inch

Weight: Approx. 5g~40g / 0.2oz~1.4oz

3G までの特性。測定方法は以下の通り

  • スペアナの入力に 30dB のアッテネータをつける
  • -20dBm のトラッキングジェネレータ出力を入力とする
  • LNAの代わりにスルーコネクタをつけてノーマライズ
  • LNAに変えて電源を入れて測定

  1. トップ
  2. tech
  3. 50K-4G LNA (25dB@0.8G) を買ってみた

SWD (Serial Wire Debug) やっててさらにトレース(printfみたいなこと)も行いたいことは多い。別途 USART を繋げて printf() デバッグしても良いが、正直めんどうくさい。

ITM とは?

Instrument Trace Macrocell の略で Cortex-M の Arm CoreSight (MCU 側のデバッグ機能) に含まれるトレース機能。トレース機能は雑にいうと printf() みたいなもので、実際 printf() を中継するのに使うこともできる。

SWO (Serial Wire Output) というトレース用のピンを使う。

semihosting との違い

セミホスティングとはが詳しいが、セミホスティングはホスト側でシステムコールの一部をホストするという仕組みで、bkpt (ブレークポイント) などで発生する例外を ARM プロセッサのデバッガインターフェイスが拾ってホスト側に中継する。

仕組み的にビルド・トレース環境とかを作るのがめんどい。

ITM の Pros. Cons.

  • ↑ 特殊なビルドが不要
  • ↓ 余計な配線が1つ必要 (SWO)

semihosting の Pros. Cons.

  • ↑ できることが多い
  • ↓ ビルドが複雑

中華 ST-Link V2 の改造

よく売ってる安い ST-Link V2 には SWO 用のピンが出ていない。機能自体はあるので配線してやる。5V と 3.3V はピンが2本ずつ重複しているので、片方を潰せば特にデメリットなく拡張できる。

↑ こういう感じでケース(カバー?)は外せる。USB コネクタ側にスライドする

↑ 31ピンが SWO 用のピン。一応親切?なのか若干配線が伸びてるので、カッターでレジストを剥してはんだづけするのが楽

↑ 今回は 5V のピンを1つ配線をカットして使うことにした。22Ωを介して外に出す。UEW 線でやってる。ちゃんとテスターで導通チェックしましょう

配線


MCU 側は SYS_JTDO_SWO の機能があるピンを設定する。STM32F401 の場合は PB3。Alternate function を設定しなければデフォルトで SWO のはず?モノによるかも

コード側

ここでは printf() を中継する前提で _write() を適当な位置に定義する

int _write(int file, char *ptr, int len) {
	for(int i = 0; i < len; i++) {
		ITM_SendChar(*ptr++);
	}
	return len;
}

あとは printf() を使うところで以下のように stdio.h を include すれば良い

#include <stdio.h> 

VSCode + Cortex-Debug の設定

Cortex-Debug は ITM のデコードをサポートしていて以下のような設定をできる。

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "OpenOCD-Debug",
            "type": "cortex-debug",
            "request": "launch",
            "servertype": "openocd",
            "executable": "build/stm32f401-usbserial-host.elf",
            "configFiles": [
                "interface/stlink.cfg",
                "target/stm32f4x.cfg"
            ],
            "postLaunchCommands": [
                "monitor reset init",
                "monitor itm port 0 on"
            ],
            "cwd": "${workspaceRoot}",
            "svdFile": "STM32F4x1.svd",
            "device": "stm32f4x",
            "preLaunchTask": "build",
            "swoConfig": {
                "cpuFrequency": 64000000,
                "source": "probe",
                "swoFrequency": 1000000,
                "enabled": true,
                "decoders": [
                    {
                        "port": 0,
                        "label": "ITM",
                        "type": "console"
                    }
                ]
            }
        }
    ]
}

これで、VSCode の「出力」タブのドロップダウン「SWO: ITM [port: 0, type: console]」に ITM 経由のログが出るようになる。type: console の場合 "\n" 区切りであることを前提にタイムスタンプを追加してくれる。

postLaunchCommandsmonitor reset init はないほうがいいかも。cpuFrequency は HCLK にあわせるのが良い。

ref

  1. トップ
  2. tech
  3. Cortex-M の SWD/ITM を使った UART を使わない printf() デバッグ