https://github.com/GoogleChromeLabs/comlink

「Comlink makes WebWorkers enjoyable.」と書いてあるが、キモは postMessage の抽象化なので、iframe 間通信にも使用することができる。ただ、origin の取り扱いをする必要があるので、ラッパーが必要。といってもラッパーも Comlink.windowEndpoint() という形で Comlink 自身に用意されている。

iframe の親でも小でも、どちらでも Comlink.expose することができる (役割は反転できる)。ただ、その際に該当する window インスタンスが必要なので、iframe の親側では小フレームのロードを待たなければならない。

comlink のレポジトリに iframe の例もある

  1. トップ
  2. tech
  3. Comlink は iframe 間通信にも使える

実行コンテキストの違い

Cordova は file: で実行される。Capacitor は http: (Android) で実行される。

この違いは案外大きい。ESM (type="module" などでロードされる ECMAScript Modules) は application/javascript でなければ実行されないという厳格なルールがあるが、file:// ではすべてのファイルに mime-type が設定されないため、実行できない。回避する方法は結局のところ localhost にサーバを立てるぐらいしかない。この点だけでももう Cordova は厳しい。

アプリケーションの本体はどこに…

Cordova はビルド時に必要なソースコードを生成する。このため実際のビルドは必ず cordova コマンドを介す。

Capacitor はソースコードのスキャフォルドを最初に生成する。レポジトリには各プラットフォームの完全なプロジェクトが生成される。このため、実際のビルドは Android Studio や Xcode など、ネイティブな環境で行われる。

  1. トップ
  2. tech
  3. 3秒でわかる Capacitor と Cordova の違い

Android Debug Bridge (adb)  |  Android Developers に従うだけ。

一旦 USB で接続して、デバイス側の adb を tcpip 経由に変更する

adb tcpip 5555

USB 接続を外して、adb connect [device ip address] を実行する

 adb connect device_ip_address

細かい手順は公式の説明にちゃんと書いてある。これで手元の端末 (Huawei P20) ではうまくいった。

これで adb は WiFi 経由でデバイスを認識しているので、adb install なども WiFi 経由で可能になる。

Android Chrome の Wi-Fi 経由デバッグ

上記手順を踏んでいれば chrome://inspect を開くと該当デバイスの Chrome インスタンスも見えているはず。そのままデバッグできる。

なぜ WiFi 経由で adb したいか

Android をホストとして USB デバイスを接続していると、USB ポートは必ず埋まってしまう。もし USB で adb 接続しようと思うと大変煩雑になる

なんか接続が切れる

デバイス側のセキュリティ要件なのかわからないが、しばらく経過すると、勝手に USB デバッグのチェックが外れたりする。よくわかってない。

とりあえず wakelock をとったほうがいいのかも

  1. トップ
  2. tech
  3. root化しなくても Wi-Fi 経由での adb はできる

GitHub Pages を GitHub Actions で PDF 化して releases にアップロードするというのをやってみた。

やりかた

  • deploy された GitHub Pages を wkhtmltopdf で PDF 化
  • ghr で PDF を releases にアップロード

が基本的なところ。GitHub Pages のデプロイは Actions よりも遥かに早く終わるので、厳密に同期をしていない (Actions で Jekyll を起動して HTML を生成するのが正攻法だけど、この方法はものすごく時間がかかってしまう)。

wkhtmltopdf は openlabs/docker-wkhtmltopdf という Docker イメージを利用した。ただし、このイメージには日本語フォントが入っていないので、ちょっと工夫する必要がある。具体的にはレンダリングしたい HTML 側で、明示的に Google Fonts などから Web Fonts としてロードしてやる必要がある。

ghr は go を入れるところからやってしまったが、たぶん ghr の releases からバイナリ落としてきて展開するほうが早いと思う。そのうち変更するかも。

実際の設定

name: document release

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
        
    - name: Set up Go 1.12
      uses: actions/setup-go@v1
      with:
        version: 1.12
      id: go
      
    - name: Convert HTML to PDF
      run: |
        docker run \
        -v ${{ github.workspace }}:/srv/jekyll  -v ${{ github.workspace }}/_site:/srv/jekyll/_site \
        openlabs/docker-wkhtmltopdf  --print-media-type https://cho45.github.io/NanoVNA-manual/ /srv/jekyll/_site/NanoVNA-manual.pdf

    - name: Upload to releases
      env:
        GO111MODULE: on
        GOPATH: /home/runner/work/
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        go get -u github.com/tcnksm/ghr
        $GOPATH/bin/ghr -u cho45 -r NanoVNA-manual -recreate -replace -n latest -b "latest" latest ${{ github.workspace }}/_site/NanoVNA-manual.pdf
  1. トップ
  2. tech
  3. GitHub Pages を GitHub Actions で PDF 化して releases にアップロード

以下のようなテーブルのとき

CREATE TABLE foo
(
   aset set('aaa', 'bbb', 'ccc')
);
  • 空文字列を SET のメンバーとして許していない
  • null 可

値を追加する

UPDATE foo SET `aset` = CONCAT_WS(',', NULLIF(aset, ''), #{member});

aset が空文字列(emptyset)のとき、これをそのままカンマで CONCAT_WS すると、",ccc" とかになり、空文字列のメンバーは許容していないため data truncated でエラーになってしまう。

CONCAT_WS は引数が null のときはそれを飛ばして連結するので、それを利用する。

ref. https://stackoverflow.com/questions/14642658/the-best-way-to-remove-value-from-set-field

値を削除する

UPDATE foo SET `aset` = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', aset, ','), CONCAT(',', #{member}, ','), ','))

もっとややこしい。というのも ",aaa" も "aaa,,ccc" も "aaa," も不正なので、こういう値にならないようにしないといけない。

備考

SET は実際は 64bit の数値なので、SET のメンバー名(文字列)を2の乗数の数値に変換する方法があれば、単にビット演算ですむ。けど、MySQL 上にはこの方法 (メンバー名を SET の数値に直接変換する) がない(と思う)。アプリケーション側で数値と文字列のマッピングを持てば SQL は簡単になるが DDL と常に整合性をとる必要があってややこしく、それなら SET じゃなく BIGINT UNSIGNED で持てばいいことになる。

なんかいい方法あったら教えてください (SET 使うな以外で)

  1. トップ
  2. tech
  3. MySQL で SET 型の UPDATE

ある程度きちんと網羅されたのがなかったので自分で書いていた。コード読みながら書いてるので、誤解がなければ正しいことが書いてあるはず。とはいえ完全に網羅できてない (electrical delay まわりとかの記述がまるっと抜けている)。

  1. トップ
  2. tech
  3. NanoVNA のユーザーガイド(マニュアル)を書いた
  1. トップ
  2. nanovna
  3. NanoVNA のユーザーガイド(マニュアル)を書いた

ソニー 広角単焦点レンズ フルサイズ FE 28mm F2 デジタル一眼カメラα[Eマウント]用 純正レンズ SEL28F20 - ソニー(SONY)

ソニー(SONY)

5.0 / 5.0

ソニー FE マウントは 55mm しか持っていなかったが、28mm もついに買ってしまった。FE マウントでは安い部類なのでさっさと買えばよかった。

memcached のデータが早々に消えることが多くなっていて困っていた。

https://lowreal.net/2016/12/14/2 で h2o の ssl-session-resumption のストア先を memcached にしているのが原因ではないか?と思ってやめてみたらなおった気がする。

NanoVNA (stm32f07) に対しての書きこみで、どの方法が早いのだろうか?と気になったので試した。対象は 95764bytes の ch.bin

結論からいうと SWD 経由の書きこみが早い。

USB 経由で dfu-util を使い書きこむ場合 → 18.7秒

(前もって DFU モードでブートする必要あり)

$ time dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D build/ch.bin
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 0483:df11
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash  "
Downloading to address = 0x08000000, size = 95764
Download        [=========================] 100%        95764 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state
dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D build/ch.bin  0.02s user 0.06s system 0% cpu 18.737 total

OpenOCD で書きこむ場合

OpenOCD からデバッグではなくプログラムを書きこむ場合

http://openocd.org/doc/html/Flash-Programming.html#Flash-Programming これの通りだけど、基本的に program コマンドを使えばよい。

program の実装は https://github.com/ntfreak/openocd/blob/master/src/flash/startup.tcl で、いくつかのコマンドを呼びだすラッパーになっている。

stm32f0x だと stm32f0x.cfg で reset 直後に 48MHz クロックを起動して JTAG の最高速度を 8MHz まで上げている。

OpenOCD 経由の ST-Link2 → 4.3秒

USB 経由と違って、いきなりコマンドを実行すれば書きこめる。

$ time openocd -f interface/stlink.cfg -f target/stm32f0x.cfg  -c "program ./build/ch.bin 0x08000000 verify reset exit"
Open On-Chip Debugger 0.10.0+dev-00930-g09eb941c (2019-09-14-00:35)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 1000 kHz
Info : STLINK V2J34S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.261130
Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : Listening on port 3333 for gdb connections
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
target halted due to debug-request, current mode: Thread 
xPSR: 0xc1000000 pc: 0x080000c0 msp: 0x20000200
Info : Unable to match requested speed 8000 kHz, using 4000 kHz
Info : Unable to match requested speed 8000 kHz, using 4000 kHz
** Programming Started **
Info : device id = 0x20016448
Info : flash size = 128kbytes
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
shutdown command invoked
openocd -f interface/stlink.cfg -f target/stm32f0x.cfg -c   0.37s user 0.83s system 27% cpu 4.365 total

OpenOCD 経由の中華 J-Link OB → 4.6秒

nRF51 で一回試したっきり使っていない怪しい J-Link OB

USB 経由と違って、いきなりコマンドを実行すれば書きこめる。デフォルト JTAG なので、ちゃんと SWD を指定しないとダメです。

$ time openocd -f interface/jlink.cfg -c "transport select swd" -f target/stm32f0x.cfg   -c "program ./build/ch.bin 0x08000000 verify reset exit"
Open On-Chip Debugger 0.10.0+dev-00930-g09eb941c (2019-09-14-00:35)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
swd
Info : J-Link ARM-OB STM32 compiled Aug 22 2012 19:52:04
Info : Hardware version: 7.00
Info : VTarget = 3.300 V
Info : clock speed 1000 kHz
Info : SWD DPIDR 0x0bb11477
Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : stm32f0x.cpu: external reset detected
Info : Listening on port 3333 for gdb connections
target halted due to debug-request, current mode: Thread 
xPSR: 0xc1000000 pc: 0x080000c0 msp: 0x20000200
** Programming Started **
Info : device id = 0x20016448
Info : flash size = 128kbytes
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked
openocd -f interface/jlink.cfg -c "transport select swd" -f  -c   0.25s user 0.52s system 16% cpu 4.628 total
  1. トップ
  2. tech
  3. stm32f0x 書きこみ速度大会

chromium Issue 884928: Web Serial API が該当する。(Chrome 系以外では実装されていない。予定もない)

実は Chrome Stable 77 でも、既に chrome://flags/#enable-experimental-web-platform-features を有効にしていると navigator.serial が生えてくるようになっている。

が、Android では(まだ)使えないみたいだ。上記イシューも Android がスコープに入っていない。

簡単に試せるページもある GitHub - GoogleChromeLabs/serial-terminal: Demo application for the Serial API.

ちなみに WebUSB での polyfill があったりする(これも google のレポジトリに入っている…) https://github.com/google/web-serial-polyfill けど、USB CDCはだいたいはOS側でインターフェイスを握られてしまうので、ドライバを無効にしたりしないといけないことに注意がいる。

現行では worker コンテキスト内で使うことができない。API 自体は有効なのだが、requestPort() してペアリングしたシリアルポートを、worker 内の getPorts で取得することができない。Issue 1005079: Serial Mojo interface not provided to Workers 報告したらイシューが立った。

また、上記に関連するのかもしれないが、そこそこ高速で通信を行うと容易にバッファが溢れてしまい、データの欠落が起こる。なので非常に大きなバッファを指定する必要がある。複数同時に read してもダメ。

  1. トップ
  2. tech
  3. Web Serial API

しばらく放っておいてどうセットアップしたか忘れたので、https://www.armbian.com/nanopi-neo-2/ armbian を改めて入れてみる。

FriendlyARM のイメージも結構更新されていそうだけど、どっちがいいか不明。しかし FriendlyARM のイメージはいまいちデキが良い感じがしなかったので、armbian Bionic server (Ubuntu系) を入れてみる。

SDカード書きこみ

Etcher で焼くだけ

初回起動

ping 192.168.0.255 とかして arp -a して 02:01:a9 からはじまる Mac アドレスがそれ。

https://docs.armbian.com によると、デフォルトで ssh が起動しており、root 、 1234 で入れるらしい。

ssh root@192.168.0.xx

すると、初回設定としてパスワード変更とユーザ追加をさせられる。やったら一回 logout して、作ったユーザーでログインしなおす。

前後して

 ssh-copy-id  cho45@192.168.0.17

とかやっておく。

初回設定

sudo armbian-config

して Personal -> Timezone の設定と、 System -> Hardware -> i2c0 にチェックを入れて再起動。

NanoHat OLED

i2c

検出できるか確認しとく。

$ sudo apt install i2c-tools
$ sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

i2c グループに自分を追加しておく

$ sudo usermod -a -G i2c
# 一回ログアウトすること
$ i2cdetect -y 0

gpio

armbian もデフォルトでは root にしか gpio へのアクセス権限がなく、gpio グループなども設定されていない。ので自分でやる必要がある.

sudo groupadd gpio
sudo usermod -aG gpio cho45
$ sudo vim /etc/udev/rules.d/80-gpio.rules
SUBSYSTEM=="gpio", PROGRAM="/bin/sh -c '/bin/chown -R root:gpio /sys/devices/platform/soc/*pinctrl/gpio*'"
SUBSYSTEM=="gpio", PROGRAM="/bin/sh -c '/bin/chmod -R ug+rw /sys/devices/platform/soc/*pinctrl/gpio*'"
SUBSYSTEM=="gpio", PROGRAM="/bin/sh -c '/bin/chown -R root:gpio /sys/class/gpio'"
SUBSYSTEM=="gpio", PROGRAM="/bin/sh -c '/bin/chmod -R ug+rw /sys/class/gpio'"
sudo udevadm control --reload-rules
sudo udevadm test --action=change /sys/devices/platform/soc/1c20800.pinctrl/gpiochip1/gpio/gpio0
$ ls -altr /sys/class/gpio/
total 0
-rw-rw----  1 root gpio 4096 Sep 15 15:45 export
drwxrwxr-x  2 root gpio    0 Sep 15 15:45 .
drwxr-xr-x 51 root root    0 Sep 15 15:45 ..
lrwxrwxrwx  1 root gpio    0 Sep 15 15:45 gpio0 -> ../../devices/platform/soc/1c20800.pinctrl/gpiochip1/gpio/gpio0
-rw-rw----  1 root gpio 4096 Sep 15 15:45 unexport
lrwxrwxrwx  1 root gpio    0 Sep 15 15:45 gpio3 -> ../../devices/platform/soc/1c20800.pinctrl/gpiochip1/gpio/gpio3
lrwxrwxrwx  1 root gpio    0 Sep 15 15:45 gpiochip352 -> ../../devices/platform/soc/1f02c00.pinctrl/gpio/gpiochip352
lrwxrwxrwx  1 root gpio    0 Sep 15 15:45 gpiochip0 -> ../../devices/platform/soc/1c20800.pinctrl/gpio/gpiochip0
lrwxrwxrwx  1 root gpio    0 Sep 15 15:45 gpio2 -> ../../devices/platform/soc/1c20800.pinctrl/gpiochip1/gpio/gpio2

node

nodejs をいれる。apt でいれると気持ちわるいことになるので公式パッケージをいれるほうがよい。

$ cd ~/
$ mkdir app
$ cd app
$ wget https://nodejs.org/dist/v10.16.3/node-v10.16.3-linux-arm64.tar.xz
$ tar xvf node-v10.16.3-linux-arm64.tar.xz
$ ln -s  node-v10.16.3-linux-arm64 node
$ cd ~/bin
$ ln -s ~/node/bin/* .
$ sudo apt install pkg-config libcairo2-dev
$ git clone git@github.com:cho45/nanohat-oled-nodejs.git
$ cd nanohat-oled-nodejs
$ npm install

動作確認

$ node index.js

systemd 化

$ ./install.sh

備考: ssh ログイン時のメッセージ

$ ls  /etc/update-motd.d

にある。/etc/update-motd.d/30-armbian-sysinfo が特に有用

  1. トップ
  2. tech
  3. NanoPi NEO2 + NanoHAT OLED に armbian