MMDVMHost / DMRGateway「ini フォーマット変更」徹底調査レポート
— なぜ変わったのか、バイナリと ini のバージョンの関係 —
1. 結論(最初に要点)
「ini フォーマット変更」は目的ではなく、結果である。
本当の変更は、MMDVMHost ⇄ DMRGateway 間の内部プロトコルから DMRC メッセージ(設定パケット)を廃止したこと。コミットメッセージそのものが答えだった:
- MMDVMHost 側:
b7d15b8“Remove the DMRC startup message.” (2026-07-13) - DMRGateway 側:
61771e2“Generate the DMRC message locally from the ini file and not via the network.” (2026-05-18)
b7d15b8 や 61771e2 のような 7 桁の英数字は、Git のコミット ID(コミットハッシュの短縮形)である。リポジトリへの変更 1 件ごとに自動で付与される固有の識別子で、これによりプログラムの「版」を正確に特定できる。git show b7d15b8 のように指定すると、その時点の差分やソースコードを参照できる。本文中の #43edd65 のように # を付けた表記も同じコミット ID を指す。[Info] セクションは「DMRC メッセージの中身を作るため」だけに存在していた。DMRC が死んだので [Info] は存在理由を失い削除された。周波数だけはモデム自身が SET_FREQ コマンドで必要とするため生き残り、本来の居場所である [Modem] へ移動した。
さらに重要な副作用として、両プログラムの master 反映日が約8週間ずれた(DMRGateway: 5/18、MMDVMHost: 7/13)。この期間、master 同士ですら噛み合わない「非互換の期間」が存在した。
2. DMRC メッセージとは何だったのか
Homebrew リピータプロトコルの設定パケット。旧設計では MMDVMHost が 10秒ごと(pingタイマー兼用) に DMRGateway へ送っていた。実際の生成コード(旧 DMRNetwork.cpp writeConfig()):
::memcpy(buffer + 0U, "DMRC", 4U);
::memcpy(buffer + 4U, m_id, 4U); // DMR ID (9桁)
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s",
m_callsign.c_str(), // コールサイン 8文字
m_rxFrequency, m_txFrequency, // RX/TX 周波数 各9桁
power, m_colorCode, slots, // 出力・CC・スロット
m_version, software); // バージョン・HW種別
return write((unsigned char*)buffer, 119U); // 119バイト
本機の DMRGateway ログに出ていたダンプがまさにこれである:
Unknown packet from the MMDVM 0000: 44 4D 52 43 ... *DMRC.:..JR2DHR * 0010: ... *4307500004307500* ... *MDVM_MMDVM_HS_Ha*
10秒間隔で繰り返し出ていたのは、ping タイマー周期そのもの。
DMRC が担っていた役割(旧設計)
- DMRGateway への自局情報の伝達 — Id・コールサイン・周波数等。DMRGateway はこれを保存し、TGIF 等のマスターへログインするときの ID と、ログイン後に送る configuration message にそのまま使った。
- キープアライブ(ping) — DMRGateway は DMRC を受けると
DMRP(4バイト)を返す。これが生存確認を兼ねた。 - 起動順序の強制 — 旧 DMRGateway は DMRC が届く(=
m_configLen > 0 && id > 1000)までWaiting for MMDVM to connect.....でブロックし、外部ネットワークを一切開かなかった。
3. なぜ廃止したのか(設計意図の分析)
コードの差分から読み取れる設計判断は「関心の分離」である。
| 情報 | 実際に使う者 | 旧設計での置き場所 | 新設計での置き場所 |
|---|---|---|---|
| RX/TX 周波数 | モデム(SET_FREQ) | MMDVMHost の [Info] → DMRC でも転送 | MMDVMHost の [Modem] |
| Id・コールサイン | マスターへのログイン | MMDVMHost の [General] → DMRC で転送 | DMRGateway.ini の [General] Id / [Info] Callsign |
| Power/緯度経度/Location/Description/URL | マスターへの設定送信 | MMDVMHost の [Info] → DMRC で転送 | DMRGateway.ini の [Info] |
旧 ini の [Info] にはこういうコメントが元々あった:
# The following lines are only needed if a direct connection to a DMR master is being used
つまり作者自身が「この情報の本当の消費者はマスター側」と認識していた。マスターと話すのは DMRGateway なのだから、その情報は DMRGateway が持つべき — これが変更の論理である。結果:
- MMDVMHost からネットワーク向けメタデータが全て消え、約315行削除の大幅な簡素化
- ping は双方向とも 4バイトの
DMRPに - DMRGateway は MMDVMHost を待たずに即座に外部ネットワークへログインできるようになった(起動順序の依存が消えた)
- 周波数は「モデムのパラメータ」という本来の位置([Modem])に正規化された
4. 時系列(非互換の期間)
| 日付 | リポジトリ | コミット | 内容 |
|---|---|---|---|
| 2026-04-06 | DMRGateway | 79edbc4 | 旧方式(DMRC受信)の最後の master コミット。hat1〜hat3 と本機がピン留めした版 |
| 2026-05-18 | DMRGateway | 61771e2 | master へ直接: DMRC 受信ハンドラ削除。DMRP のみ受理、他は Unknown packet。Id/Info を自分の ini から読む方式に |
| 2026-05-18 | MMDVMHost | bdc1aed | 同日に作者がホスト側も変更。ただし Remove_DMRC ブランチに留まる |
| 2026-05-29 | MMDVMHost | 43edd65 | master はまだ旧方式。実行ファイル名変更(MMDVMHost→MMDVM-Host)のコミット。本機がピン留めした版 |
| 2026-07-13 | MMDVMHost | b7d15b8 | ブランチが master へ合流。[Info] 削除・周波数 [Modem] 移動・DMRC 送信廃止 |
| 2026-08-01〜 | 両方 | dea6e9b / 2a3306d | 本機が最初に clone してしまった「最新版」 |
5. 互換マトリクス(本調査の核心)
5-1. MMDVMHost バイナリ × MMDVM-Host.ini
パーサーはセクション厳格で、フォールバックは一切ないことをコードで確認した。旧 Conf.cpp は SECTION::INFO の中でのみ、新 Conf.cpp は SECTION::MODEM の中でのみ RXFrequency を読む。
| バイナリ \ ini | 旧 ini(周波数が [Info]) | 新 ini(周波数が [Modem]) |
|---|---|---|
| 旧バイナリ(〜2026-07-12, #43edd65 含む) | ✅ 正常 | ❌ 周波数 0 → 起動ループ |
| 新バイナリ(b7d15b8 以降) | ❌ 周波数 0 → 起動ループ | ✅ 正常 |
失敗のメカニズム(両方向とも同一):
該当セクションに周波数キーが無い → m_modemRXFrequency が初期値 0 のまま → Modem::open() 内の setFrequency() が 0Hz を送信 → ADF7021 ファーム側が帯域外として NAK → open() 失敗 → (systemd Restart=on-failure なら)無限再起動ループ
ログの決定的サイン: TX Frequency: 0Hz の表示、および SET_FREQ への NAK。
5-2. MMDVMHost × DMRGateway(localhost プロトコル)
| ホスト \ ゲートウェイ | 旧 GW(〜79edbc4) | 新 GW(61771e2 以降) |
|---|---|---|
| 旧ホスト(DMRC を10秒毎送信) | ✅ 正常(hat1〜3・本機の構成) | ⚠️ 動くが異常: Unknown packet が10秒毎に出続け、GW は自分の ini 既定値(Id=12345, G9BF)でマスターへログイン → 未登録 ID のため TGIF はタイムアウト |
| 新ホスト(DMRP のみ) | ❌ GW が Waiting for MMDVM to connect..... で永久待機(DMRC が永遠に来ないため。ソースの待機条件 m_configLen > 0 && id > 1000 を確認済み) | ✅ 正常(ただし DMRGateway.ini に自局の Id・[Info] を記入することが必須) |
5-3. 正しい組み合わせは 2 つだけ
【旧セット】 MMDVMHost 〜#43edd65 + 旧ini([Info]) + DMRGateway 〜#79edbc4 【新セット】 MMDVMHost b7d15b8〜 + 新ini([Modem]) + DMRGateway 61771e2〜 + DMRGateway.iniに自局Id/Info記入
6. 本機で起きたことの再解釈(重要な訂正)
この調査により、構築時の事象の解釈が一部変わる。
6-1. 最初の TGIF タイムアウトの真因
当時のログ:
DMR Network 3 Parameters
Id: 12345 ← ★
TGIF_Network: configuration message: G9BF 435000000435000000... ← ★
TGIF_Network, Connection to the master has timed out, retrying connection
当時は「Id: 12345 は MMDVMHost 接続前の仮表示」と解釈したが、誤りだった。新 DMRGateway のコードは:
if (id == 0U)
id = m_id; // ← m_conf.getId() = DMRGateway.ini の [General] Id
であり、雛形既定値の Id=12345 で実際に TGIF へログインを試みていた。G9BF / 435MHz も新 ini 雛形の [Info] 既定値である。12345 は未登録 ID なので TGIF が応答せずタイムアウトした — これが真因である可能性が極めて高い。
Id: 440072899 と正しい値を示していることが裏付けになる。6-2. 「Unknown packet」の10秒間隔
DMRC 送信は ping タイマー(10秒)に載っている。ログのタイムスタンプ 07:36:40.283 → 07:36:50.291 の間隔がぴったり10秒だったのは、この周期の直接の現れ。
6-3. 新 DMRGateway が即座に TGIF へ接続開始した理由
旧 GW は Waiting for MMDVM to connect..... と待つのに、新 GW は起動直後に TGIF へ向かった。これは新設計で「MMDVMHost を待つ必要がなくなった」(設定を自前の ini から得る)ため。ログの挙動差もコードと一致する。
7. もし新セットへ移行するなら(参考手順)
将来、最新版に追従したくなった場合の要点。4項目を同時に切り替える。
- MMDVMHost を最新化する。
cd /opt/MMDVMHost git stash && git checkout master && git pull make clean && make -j$(nproc)
MMDVM-Host.iniを新フォーマットへ移行する。新雛形のMMDVM-Host.iniを元に作り直し、周波数は[Modem]セクション内にRXFrequency=/TXFrequency=を書く。[Info]セクションは存在しない(書いても読まれない)。- DMRGateway を最新化する(
git stash popで TGIF 設定を書き戻す)。cd /opt/DMRGateway git stash && git checkout master && git pull make clean && make -j$(nproc) git stash pop
DMRGateway.iniに自局情報を追記する(新方式の必須事項)。[General] Id=440072899 ← これがマスターへのログインID。雛形の12345のままでは絶対に動かない [Info] Callsign=JR2DHR RXFrequency=430750000 TXFrequency=430750000 Power=1 ColorCode=1 Duplex=0
8. 教訓
- git pull は「対」で考える。 MMDVMHost と DMRGateway は独立リポジトリだが、localhost プロトコルで密結合している。片方だけの更新が最も危険で、master 同士ですら8週間の不整合期間が実在した。
- コミットメッセージが最短の答えだった。 “Remove the DMRC message” — この一行に、ini 変更・Unknown packet・Id=12345・起動順序の変化、すべての説明が含まれていた。障害調査では
git logを最初に読む価値がある。 - パーサーはセクション厳格・フォールバック無し。 「キーはあるのに読まれない」は MMDVM 系 ini の典型的な罠。キー名だけでなく、どのセクションの中にあるかまで一致させる必要がある。
- 雛形既定値でログインしてしまう設計に注意。 新 DMRGateway は ini を埋めないと Id=12345/G9BF で実ネットワークへ出て行く。テンプレートをコピーしたら、まず [General] Id と [Info] を自局値にする。
- 症状からの推理は、ソースで裏を取るまで確定しない。 「ESSID 重複」は筋の通った仮説だったが、真因は別(Id=12345)だった。ログの
Id: 12345という小さな違和感が、実は最大の手がかりだった。
付録: 検証に使った主なコマンド
git clone https://github.com/g4klx/MMDVMHost git clone https://github.com/g4klx/DMRGateway # 変更コミットの特定と差分 git log --oneline --since="2026-05-01" git show b7d15b8 --stat git show b7d15b8 -- MMDVM-Host.ini # [Info]削除・[Modem]へ移動の実diff git show b7d15b8 -- DMRNetwork.cpp # writeConfig(DMRC 119B)→writePing(DMRP 4B) git show 61771e2 -- DMRGateway.ini # [General]Id / [Info]新設 git show 61771e2 -- MMDVMNetwork.cpp # DMRC受信ハンドラ削除の実diff # 系譜の検証 git merge-base --is-ancestor bdc1aed 43edd65 # → NO(別ブランチ) # パーサーのセクション厳格性 git show 43edd65:Conf.cpp | grep -B1 '"RXFrequency"' # 旧: SECTION::INFO 内のみ git show dea6e9b:Conf.cpp | grep -B1 '"RXFrequency"' # 新: SECTION::MODEM 内のみ # 旧GWの待機条件 / 新GWのId供給元 git show 79edbc4:DMRGateway.cpp # m_configLen>0 && id>1000 まで待機 git show 61771e2:DMRGateway.cpp # if (id==0) id = m_id (= ini の Id)
追補(2026-08-27): 説明・対比表・新旧の具体的な書き方
A. DMRC とは何か(かみ砕いた説明)
DMRC = 「DMR Configuration」、自局の名刺パケット。
MMDVMHost が DMRGateway に「私はこういう局です」と自己紹介する 119 バイトのデータで、中身はコールサイン・DMR ID・RX/TX 周波数・出力・カラーコード・スロット・機種名。先頭 4 バイトが文字 DMRC。
旧設計を名刺に例えると: MMDVMHost は 10 秒ごとに名刺を差し出し続け(生存確認の ping 兼用)、DMRGateway はその名刺を 2 つのことに使った。①TGIF へのログイン ID(名刺の 440072899 を使用)、②TGIF に送る自己紹介文(ログの configuration message: JR2DHR 430750000...)。DMRGateway は「名刺を預かってマスターへ取り次ぐ受付係」であり、だから名刺が届くまで Waiting for MMDVM to connect..... と待った。
新設計は「受付係が自分の ini に名刺を持つ」方式。MMDVMHost は名刺を配らず、「生きてます」の 4 バイト DMRP だけ送る。DMRGateway は自分の ini の [General] Id と [Info] から名刺を自作する。新旧を混ぜると、旧ホストが差し出す名刺を新受付が「知らない紙」と捨てる(= Unknown packet)。
B. 対比表
表1: バージョン年表
| 日付 | リポジトリ | コミット | 世代 | 内容 |
|---|---|---|---|---|
| 2026-04-06 | DMRGateway | 79edbc4 | 旧 | 旧世代の最終版。hat1〜3・本機が採用 |
| 2026-05-18 | DMRGateway | 61771e2 | 新 | DMRC 受信廃止。Id/Info を自分の ini から読む方式へ |
| 2026-05-29 | MMDVMHost | 43edd65 | 旧 | まだ旧世代(DMRC 送信)。実行ファイル名変更。本機が採用 |
| 2026-07-13 | MMDVMHost | b7d15b8 | 新 | DMRC 送信廃止。[Info] 削除、周波数を [Modem] へ |
| 2026-07-20 | DMRGateway | d94c67d | 新 | 新 ini 雛形のキー名 typo(TXFRequency)を修正 |
| 2026-08 時点 | 両 master | dea6e9b / 2a3306d | 新 | 本機が最初に誤って clone した版 |
5/18〜7/13 の約 8 週間は、master 同士でも新旧が混在する「非互換の期間」。
表2: 世代の見分け方
| 見る場所 | 旧世代 | 新世代 |
|---|---|---|
| MMDVM-Host.ini | [Info] に周波数がある | [Info] が無く、周波数は [Modem] 内 |
| MMDVMHost の git | git merge-base --is-ancestor b7d15b8 HEAD → NO | 同 → YES |
| DMRGateway.ini | [General] に Id= が無い | [General] Id= と [Info] Callsign= 等がある |
| DMRGateway 起動ログ | Waiting for MMDVM to connect..... と待つ | 待たずに即マスターへ接続開始 |
表3: 組み合わせ対比表(6 パターンの運命)
| # | Host バイナリ | Host ini | GW バイナリ | 結果 |
|---|---|---|---|---|
| 1 | 旧 | 旧([Info]) | 旧 | ✅ 正常(hat1〜3・本機の構成) |
| 2 | 新 | 新([Modem]) | 新 + GW ini に自局 Id/Info 記入 | ✅ 正常 |
| 3 | 新 | 旧 | — | ❌ 周波数 0Hz → SET_FREQ NAK → 起動ループ |
| 4 | 旧 | 新 | — | ❌ 同上(パーサーが逆セクションを読まない) |
| 5 | 旧 | 旧 | 新 | ⚠️ Unknown packet 10秒毎 + GW が既定 Id=12345 でログイン → タイムアウト(本機が最初に踏んだ) |
| 6 | 新 | 新 | 旧 | ❌ GW が名刺(DMRC)待ちで永久に Waiting |
C. 結局どのバージョンを使うべきか
今は「旧セット」継続が正解(本機・hat1〜3 の現構成)。理由: ①既存 3 台と手順書・メモ資産が全部この世代で揃っている ②動作実績とハマりどころを把握済み ③新旧に無線側の機能差はほぼ無い(変わったのは内部の設定伝達方式)。
新セットも条件付きで使える: 4 点を同時に新世代へ切り替え、DMRGateway.ini に自局情報を記入すること。移行は全機一斉が鉄則。
長期的には新セット移行が避けられない(旧世代に今後のバグ修正は入らない)。急ぐ必要はなく、D-STAR/YSF 追加などで大きく触るタイミングで全機まとめて、が現実的。
D. 新旧の書き方 具体対比
D-1. MMDVM-Host.ini — 変わるのは周波数の置き場所だけ
旧(#43edd65)— [Info] セクションに書く:
[General] Callsign=JR2DHR Id=440072899 ... [Info] ← このセクションが存在する RXFrequency=430750000 ← ここに書く TXFrequency=430750000 Power=1 Latitude=0.0 Longitude=0.0 Location=Nowhere Description=Multi-Mode Repeater URL=www.google.co.uk [Modem] Protocol=uart UARTPort=/dev/ttyUSB0 ... ← 周波数はここには書かない
新(b7d15b8 以降)— [Modem] セクションに書く:
[General]
Callsign=JR2DHR
Id=440072899 ← ここは変わらず
...
← [Info] は存在しない(書いても無視される)
[Modem]
Protocol=uart
UARTPort=/dev/ttyUSB0
LocalPort=3335
RXFrequency=430750000 ← [Modem] の中に書く
TXFrequency=430750000
TXInvert=1
...
Power/緯度経度/Location/Description/URL は新ホストには書く場所そのものが無い(DMRGateway 側へ引っ越した)。
D-2. DMRGateway.ini — 新世代では書くべきものが増える(最重要)
旧(#79edbc4)— 自局情報は書かない:
[General] Timeout=10 ← Id= は存在しない RptAddress=127.0.0.1 ... [Info] Latitude=0.0 ← 位置情報だけ。コールサイン・周波数・Id は無い Longitude=0.0 Location=Nowhere ...
自局の Id・コールサイン・周波数は MMDVMHost から DMRC で自動的に届くので書く必要がない(書く場所も無い)。
新(61771e2 以降)— 自局情報を自分で書く(必須):
[General] Id=440072899 ← ★必須。マスターへのログイン ID はここ。 Timeout=10 雛形の 12345 のままでは未登録 ID でログイン失敗 ... [Info] Callsign=JR2DHR ← ★新設。自局値に書き換える(雛形は G9BF) TXFrequency=430750000 ← ★新設 RXFrequency=430750000 Power=1 ColorCode=1 Duplex=0 ← 単信なら 0 Slot1=1 Slot2=1 Latitude=0.0 ...
一言まとめ: 旧は「名刺はホストが配る(GW には書かない)」、新は「名刺は GW の ini に自分で書く(書かないと偽名 G9BF / 12345 で出て行く)」。
D-3. 小さな罠: 初期テンプレートのキー名 typo
TXFRequency / RXFRequency(R が大文字)と打ち間違っており、パーサーは正しい TXFrequency / RXFrequency を期待するため、雛形どおり書くと周波数が黙って無視された(d94c67d で修正済み)。「キー名は 1 文字違うだけで黙って無視される」という MMDVM 系 ini の性質を象徴する例。新セットへ移行する際はキー名を現行雛形からコピーすること。あわせて読みたい(関連記事)
- USB HAT MMDVM 環境構築手順書(Debian 直接インストール版 / amd64 / TGIF 直結版)
- USB HAT MMDVM 環境構築手順書
- パケットキャプチャで電波の中身を見る ─ DMR フレームの読み方
- DMR パケット解析 実践ガイド
- END フレームはどこへ消えた — Semi Repeater Mode のターミネータ欠落と「ウォッチドッグ擬似終端」
- XLX168-X ↔ TGIF 44833 ブリッジ 手順書(SSH 運用版)
🏛 JJ2YYK あいちデジタルコミュニケーションハムクラブ