27-Sep-2026
[紙のお値段はやっぱり意識しちゃいます]

電気通信術の受信練習、書き取りなので紙を使うんですよ。

日頃は100円ショップで売られているB5のB罫ルーズリーフ、今だとダイソーの70枚入りを使っています。今後額表への対応を行うことになるのですが、そうなると専用の受信用紙が必要になる訳で。情報通信振興会の和文受信用紙(100枚・税込\385+送料)は持っているものの、まだ手をつけていません。なにしろ額表+本文60文字しか書けないので、額表をやらなければ勿体ないです。

B5のコピー用紙500枚を\300〜\500くらい(+送料)で入手してplus TK2Sさんの様式を印字する方がまだ安い気がしますが、とはいえ本文60文字/枚は以下略。オークションで見た(日本)軍用の電報頼信紙でも本文100文字/枚、流石にこれを練習に使うのも…

試験を受けることにした場合は練習の仕上げで本文60文字/枚の受信用紙を使うとして、それまでの間に使う本文240文字/枚の紙というのを作ってみました。事情によりA4サイズになっていますが、用紙サイズに合わせて印刷すればB5サイズになりますということで。

むしろ額表練習に特化した、額表だけという様式を作った方が良いのかもしれません。時刻で使う数字の略体、なんなんですかアレは💢(昨日から練習を始めたのでまだ全然取れません)ということで、こちらも作ってしまいました。56.1kg(18:45)

22-Sep-2026
[折角なので]

AliExpressで見かける電鍵接続用のUSBドングルに使われていると思われる、MorseLink_connectorのファームウェア(MorseLink_firmware.hex)のアドレス33ABH〜にある各種USB descriptorを、AIの力も借りて解析してみました(USB standard descriptorはともかく、HID report descriptorの解釈は流石にヒトの手に余る)。

ざっと見ると、こんな感じの複合デバイスでしょうか。

USB CDC-ACMインタフェース(bInterfaceNumber=0)
bEndpointAddress=0x81(Interrupt/IN, wMaxPacketSize=8, bInterval=64)
USB CDC-Dataインタフェース(bInterfaceNumber=1)
bEndpointAddress=0x02(Bulk/OUT, wMaxPacketSize=64), bEndpointAddress=0x82(Bulk/IN, wMaxPacketSize=64)
USB HID/boot keyboardインタフェース(bInterfaceNumber=2)
bEndpointAddress=0x83(Interrupt/IN, wMaxPacketSize=16, bInterval=10)

HID report descriptorに定義されているものはこの三つ。

Generic Desktop/Keyboard(Report ID=1)
その辺にある普通のキーボード。先頭2byteのうち1byteをメタキー、1byteはpadding。残り6byteをスキャンコードとして使用。
Consumer Devices/Consumer Control(Report ID=2)
これもその辺にある普通のキーボードの付加機能。
Generic Desktop/Mouse(Report ID=3)
その辺にある普通のマウス。中ボタン/ホイールありなので1byteのボタンステータス+移動量3byte。

電鍵を単純に繋ぐだけならここまでリッチな作りにする必要は無いはずなのですが…MorseLinkのdialog/key_modifier_dialog.pyを見るに、このアプリからUSB CDCインタフェースを通じて、USB HID側の挙動を変更可能にしているように見えます。_build_write_payloadがこんな感じのパケットを組み立てています(key3_hex, key3funcを設定している割に、bytes[]にkey3fが無いのが謎ですが…おそらくkey3については結果的にkeyboard扱いとなるのでしょう)。

offsetcontent
+00x02
+1key1_hex
+2key2_hex
+3key3_hex(0x77)
+4key1func
+5key2func
+6key3func(0x00)
+7key1f
+8key2f
+9padding(0xff, 144byte)
+1530x00
+1540x03

key?_hex, key?func, key?fの戻り値は同じソース内の_collect_single_key_payloadで決定しますが、これはこういう動作でしょうかね。

key?_hexkey?funckey?f
mousekey_hex(0x01, 0x02, 0x04)0x040x00
function0x800x000xff
keyboardkey_hex(ASCII code)0x000xff

おそらく、AliExpressで売られている電鍵接続用のアダプタをそのまま繋げても、デフォルトの設定次第では難儀する可能性があるのかもしれません。MorseLinkのデフォルトは81, 87…「qw」を想定しているようで、もしかするとアダプタ側もこれに準じている可能性がありそうです。

♪

ddci-ch552の性能を見るために、TAM-KEYER102を繋げてログを取ってみましたが、USB Full-speed/bInterval=1の効果はちゃんと出ており、±1msの範囲で収まっています(前にも書いた通りで、TAM-KEYER102はkey onよりもoffの方が少し長いです)。56.6kg(23:15)

21-Sep-2026
[おぼえがき]

skif-arduino.inoないしddci-ch552.ino(これを書いている時点における、GitHubのmasterブランチのコードをコピーしています)を見ていて、おそらく今後コードを見返した際にどういう動きをしているんだこれ?となりそうなのでメモを残すことにします。ddci-ch552はskif-arduinoのコードをベースにしているので、まずはskif-arduinoから。

・割り込みハンドラの動作 (skif-arduino)

Timer1を使い、125μs毎に割り込みを発生させる。

  1. 割り込み発生時点におけるGPIOの状態をCurrPinStatusに記録。
  2. 時間計測用のカウンタ(Counter)を増やす。
  3. eager debounce用のカウンタ(PinMaskCounter)を減らす。
  4. loop()側をキック。

・loop()の動作 (skif-arduino)

タイマ割り込みが発生するまでsleep命令で待つ。割り込み発生後、以下の処理を行う。

  1. 保持しているGPIOの状態(PrevPinStatus)と割り込みハンドラで取得したGPIOの状態(CurrPinStatus)の変更箇所(changed)を求める。
  2. eager debounce用のカウンタ(PinMaskCounter)が0ならPrevPinStatus、そうでなければCurrPinStatusを使用するようマスク(useprev)を生成。
  3. changedをuseprevでマスクした結果(ここでeager debounceが掛かる)信号変化ありと判断した場合か、時間計測用のカウンタ(Counter)がオーバーフローした場合はこれ以降の処理を実行。そうでなければここで処理を打ち切る。
  4. PrevPinStatusは信号変化の起こる前のピン状態を保持しており、これとその経過時間(Counter)を送信。
  5. PrevPinStatusを、CurrPinStatusとuseprevを使って更新。
  6. 時間計測用のカウンタ(Counter)を0に初期化。
  7. 信号変化のあったピンについてはPinMaskCounterを設定。

ddci-ch552も大体これと同じような流れになりますが、時間計測を行わないのでCounterが無くなることと、信号変化の前ではなく後の情報を送信するので少し変わります。

・割り込みハンドラの動作 (ddci-ch552)

Timer2を使い、1ms毎に割り込みを発生させる。

  1. 割り込み発生時点におけるGPIOの状態をCurrPinStatusに記録。
  2. eager debounce用のカウンタ(PinMaskCounter)を減らす。
  3. loop()側をキック。

・loop()の動作 (ddci-ch552)

タイマ割り込みが発生するまで待つ。割り込み発生後、以下の処理を行う。

  1. 保持しているGPIOの状態(PrevPinStatus)と割り込みハンドラで取得したGPIOの状態(CurrPinStatus)の変更箇所(changed)を求める。
  2. eager debounce用のカウンタ(PinMaskCounter)が0ならPrevPinStatus、そうでなければCurrPinStatusを使用するようマスク(useprev)を生成。
  3. PrevPinStatusを、CurrPinStatusとuseprevを使って更新(ここでeager debounceが掛かる)。
  4. 信号変化のあったピンについてはPinMaskCounterを設定。
  5. ピンの信号変化があった場合はステータスを送信。ステータスはPrevPinStatusに基づく。

ddci-ch512、この日記を書く際にコードを見直していたら豪快に間違えている箇所があったので、直しておきました。コードをよくよく見てみると、full-speedで動いている割にbInterval=10なので、今後はdescriptor周辺も直していく必要がありそうです。折角なので、NKRO(N-key rollover)キーボード風に作り直してみます…メインのロジックを変えずに、report descriptorを変えるだけで済みますからね。

なお、AliExpressではCH552Gを搭載したこの手のアダプタが数多く売られているようです(例)。商品の紹介動画を見る限りでは、マウスの左右ボタンとして振る舞うように見えます。MorseLinkなるソフトウェアも使っているようです。アダプタの回路図はMorseLink---CW电键转接器やMorseLink_connectorに出ていますが、ファームウェアは.hexの形でしか存在せず、ソースコードは秘匿されているといって良いでしょう。

♪

21日恒例の、JMH電波予報です。前回は20-Jul-2026。

t202609211139.jpg

受信直前の電波状態があまり良くないように思えたので、今回は7MHz帯で受信しています。56.7kg(24:00)

20-Sep-2026
[欲しかったので]

手近にあったWeActStudio CH552CoreBoardを使って、DDCI01っぽいもの…いわゆるVBandアダプタを作ってしまいました。

timg_20260920_142028_057.jpg timg_20260920_142100_316.jpg timg_20260920_142216_830.jpg

車輪の再発明なのは分かっているのですが、USB full-speed deviceな電鍵接続用アダプタが今すぐ欲しかったので。自作する場合はCH552ではなく、Raspberry Pi Pico/2(RP2040/RP2350)やArduino Leonardo(ATmega32u4)でアダプタを作ることが多いように見えます。キー割り当ても、VBand標準の[]以外に左右Ctrl/左右マウスボタン(Morsecode.World)、xz(Vail)、ei(morsecode.me - 閉鎖?)、と色々流派があるようですね。

ところで、この手のアダプタは長点・短点パドルを同時押しした際に一つのUSB interrupt packetにまとまって送信されるものなのでしょうか?それとも1周期ずれて別々になるのでしょうか?(今回作ったddci-ch552は一つにまとめて送信するよう作ったつもりです、DDCI01もそう作られていたので)

…今回作ったアダプタでCW GalaxyのスコアがDDCI01の時よりも上がったかどうかについては、ノーコメントということで。56.9kg(23:10)

13-Sep-2026
[JavaScript、難しいですね…]

10-Sep-2026にweb app化したskif-test(.js)、ちょこちょこいじってバグを仕込んだり直したりの繰り返しです。概ね出来上がっている、とは思うのですが…サイドトーンをどうやって入れてみたもんかなーと悩んでいます。現状でも困らないのですが、あったらいいなって。

試しにmain.js側へ仕込んでみたものの、ちゃんと動きません。これは当然と言えば当然で、実際のキーon/offの現場でサイドトーンon/offをしないとマトモに鳴りません。なので、HID(Keyboard/Mouse), Serial(DSR/DTR signal)では追加できそうですが、SKIFはインタフェース(skif-arduino)側での対応と考えています。

それにしても…むしろこんなツールいじってる暇があるならCW Galaxyで遊ぶ方がはるかに練習になるような気が。DDCI01もありますし(左右Ctrlではなく[]モード推奨)、これにHK-705(旧モデル)・改を繋げてちょっくら参戦してきます。57.3kg(21:10)

10-Sep-2026
[という訳で]

web app化してみました。

AIと相談しながら、AIの出してきたコードを適当に写経というスタイルで書いているので、AIの出したものをそのままコピペはしていないです。AIの支援を少なからず受けている以上、反AI派から「AIに書かせたコード!死ね!」等の罵声が飛んで来ることは想定済みです。

操作方法の説明は…要りますかね?必要な設定を行ってスタートボタンを押し、キーなりマウスなりをがしがし叩くだけなんですけど。シリアルポートのDSR-DTR線を使うインタフェースにも対応させています。

肝心のskif対応は、これから行います。対応前ですがGitHubには上げちゃったので、GPLにはしておきますがいじりたければ好きにforkしてください。なので機能追加等の要望については(自分が必要とするもの以外は)一切応じませんので、悪しからず。56.8kg(24:40)

11-Sep-2026補足:skif対応を追加しました。WebSerialって、データが来るまでずっと待たされるというのは結構癖のあるAPIだなーと思いました。

12-Oct-2026補足:単語間の表示を見直したのと、verbose modeをmsec単位だけでなく短点の長さに対する比率で表示するモードを追加しています。

08-Sep-2026
[キー入力をリアルタイムに取れるようになったので]

これを利用したモールス符号の送信練習プログラムを作っているところです。以前作った、skif-testを拡張する形で作っているのですが…大体動くとはいえ、ちょっとこれは見苦しいかなという箇所を潰すのに手間取っている状況です。一応、専用インターフェース(skif-arduino)を用意しなくてもlibinputによりキーボード/マウスでの操作もできるようにはしています(ただし、こちらには色々と制約があります)。

エレキーを繋げて簡単に叩いてみれば確かに符号から文字になるものの、縦振電鍵ではマトモに文字になりません。その練習を支援するためのプログラムと言えばそうなのですが、きちんと打てるようになるまでに要する時間、縦振電鍵よりもエレキーの方が短くて済むのかなーって。

ふと思ったのですが、この手のアプリはJavaScriptで書いてweb app化した方が良いのでしょうかね?56.7kg(23:45)