docs: подробный README (разбор проекта при переносе в Gitea)
Старый README сохранён как README.upstream.md.
Этот коммит содержится в:
+70
-104
@@ -1,119 +1,85 @@
|
|||||||
# 0DMRMaster
|
# 0DMRMaster (форк)
|
||||||
Private DMR master server. Version 0.5.
|
|
||||||
Copyright ©2025 Alexander Mokrov, UR6LKW.
|
|
||||||
|
|
||||||
This project is currently in public alpha and is under active development.
|
Частный DMR-мастер-сервер на Python: реализация протокола Homebrew DMR (того же, что используют BrandMeister и HBlink), к которому подключаются хотспоты и репитеры, плюс декодирующий UDP-прокси для анализа трафика и веб-дашборд. Позволяет поднять собственную закрытую DMR-сеть, не завязанную на публичные мастера.
|
||||||
Don't use it in production environment, interfaces may change.
|
|
||||||
|
|
||||||
|
Это форк проекта **0DMRMaster** Александра Мокрова (UR6LKW), оригинал — `https://github.com/olympy/0DMRMaster`, лицензия GPL-3.0 (файл `LICENSE`). Копия взята для эксплуатации у себя — как мастер-сервер и как инструмент разбора DMR-пакетов рядом с XLX-рефлектором. Документация оригинального проекта (описание протокола, roadmap, список источников ETSI) сохранена в [README.upstream.md](README.upstream.md).
|
||||||
|
|
||||||
## License
|
## Отличия от оригинала
|
||||||
This program is free software: you can redistribute it and/or modify
|
- `2025-06-19` — единственный собственный коммит: `localmaster_EXAMPLE.py` переименован в `localmaster.py`. Содержимое файла не изменено (`similarity index 100%`).
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
Смысл правки: в оригинале `localmaster.py` — локальный конфиг-файл запуска, он перечислен в `.gitignore` (`/localmaster.py`) и в репозитории лежит только пример. В этой копии рабочий файл запуска взят под контроль версий, чтобы разворачивать сервер клонированием без ручного копирования примера. Побочный эффект: любые локальные настройки (в том числе список разрешённых peer ID и паролей в `ListPeerAuth`) при последующих правках попадут в историю git.
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
Кода самого проекта (`dmrtools/`, `api/`, `dashboard/`) владелец не менял — он полностью соответствует апстриму по состоянию на 2025-06-01.
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
## Стек
|
||||||
|
- Python 3.11+, asyncio (`asyncio.DatagramProtocol` для UDP).
|
||||||
|
- FastAPI + uvicorn — HTTP API и раздача дашборда; `bitarray`/`bitstring` — разбор битовых полей DMR; `dmr-utils3` (BPTC-декодирование Embedded LC); pydantic. Полный список — `requirements.txt`.
|
||||||
|
- Дашборд — статический HTML + JS без фреймворков.
|
||||||
|
- Работает на Linux и Windows. Специального железа (AMBE-чипов) не требуется: голос не транскодируется, кодек AMBE пока не реализован.
|
||||||
|
|
||||||
## Overview
|
## Структура
|
||||||
This project contains:
|
- `localmaster.py` — точка входа: наследник `DMRMaster`, в методе `config()` задаётся авторизация пиров и регистрируются приложения. Здесь же включается «попугай» (`ParrotApp(9990)`).
|
||||||
1. An implementation of homebrew dmr protocol (which is used by brandmeister and hblink). Not yet complete, but sufficient for #2 and #3.
|
- `udpproxylogger.py` — второй исполняемый скрипт: UDP-прокси между хотспотом и чужим мастером с hex-логом и декодированием пакетов (L1 MMDVM + L2 ETSI).
|
||||||
1. Decoding UDP proxy
|
- `relog.py` — повторный разбор ранее сохранённого лога (строки `HD: <hex>`) тем же декодером.
|
||||||
1. Basic private dmr master server
|
- `dmrtools/dmrmaster.py` — каркас сервера: разбор аргументов командной строки, логирование, запуск UDP-сервера и API.
|
||||||
|
- `dmrtools/dispatcher.py` — маршрутизация пакетов между пирами и приложениями.
|
||||||
|
- `dmrtools/peer.py`, `peer_controller.py` — состояние подключённых репитеров/хотспотов и конечный автомат логина (RPTL/RPTK/RPTC).
|
||||||
|
- `dmrtools/auth.py` — политики доступа: `AllowAllPeerAuth` (пускать всех), `DenyAllPeerAuth`, `ListPeerAuth({id: 'пароль'})` со сверкой SHA-256 хэша с солью.
|
||||||
|
- `dmrtools/call.py` — сборка голосового вызова из потока пакетов.
|
||||||
|
- `dmrtools/parrot_app.py` — приложение-эхо: записывает вызов на свой ID и проигрывает обратно с задержкой.
|
||||||
|
- `dmrtools/app.py` — базовые интерфейсы приложений (`App`, `IAppCallInterceptor`, `IAppDispatcher`).
|
||||||
|
- `dmrtools/udpproxy.py` — многоклиентский UDP-прокси (сессия на каждый адрес клиента).
|
||||||
|
- `dmrtools/network.py`, `asyncnetwork.py` — интерфейсы отправки/приёма датаграмм и их asyncio-реализация.
|
||||||
|
- `dmrtools/dmrproto/mmdvm_l1.py` — пакеты Homebrew/MMDVM (DMRD, RPTL, RPTPING, DMRA и т.д.), расчёт хэша пароля.
|
||||||
|
- `dmrtools/dmrproto/etsi_l2.py`, `lc_util.py`, `enums.py`, `base_fields.py`, `factory.py` — разбор внутренней структуры DMR по ETSI TS 102 361: Link Control, тип голосового кадра, Talker Alias.
|
||||||
|
- `dmrtools/pphex.py` — hexdump для логов.
|
||||||
|
- `api/dmrapi.py` — FastAPI-приложение: `/api/dashboard`, `/api/peers`, `/api/calls`, монтирование статики.
|
||||||
|
- `dashboard/index.html`, `dashboard/app.js` — веб-дашборд, опрашивающий API.
|
||||||
|
- `doc/dashboard-screenshot.png` — скриншот дашборда для README.
|
||||||
|
|
||||||
### Installation
|
## Как запустить/установить
|
||||||
1. Check basic requirements:
|
```sh
|
||||||
- Linux or Windows
|
python -m venv venv
|
||||||
- Python 3.11+
|
. venv/bin/activate
|
||||||
1. Clone/download the repo.
|
python -m pip install --upgrade pip
|
||||||
1. Create environment and install requirements (linux example):
|
pip install -r requirements.txt
|
||||||
|
python localmaster.py
|
||||||
```
|
```
|
||||||
$ python -m venv venv
|
Остановка — `Ctrl+C`.
|
||||||
$ . venv/bin/activate
|
|
||||||
$ python -m pip install --upgrade pip
|
По умолчанию сервер слушает `62031/udp` (DMR) и `8000/tcp` (API и дашборд):
|
||||||
$ pip install -r requirements.txt
|
- API: `http://<сервер>:8000/api/dashboard`
|
||||||
|
- Дашборд: `http://<сервер>:8000/dashboard/index.html`
|
||||||
|
|
||||||
|
UDP-прокси с логом:
|
||||||
|
```sh
|
||||||
|
python udpproxylogger.py <listenip> <listenport> <serverip> <serverport> [-l log.txt]
|
||||||
|
```
|
||||||
|
Повторный разбор лога:
|
||||||
|
```sh
|
||||||
|
python relog.py <входной-лог> [-l log.txt]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration
|
## Конфигурация
|
||||||
Copy `localmaster_EXAMPLE.py` to `localmaster.py` and edit.
|
Аргументы `localmaster.py` (обрабатываются в `dmrtools/dmrmaster.py`):
|
||||||
|
- `-i, --interface` — интерфейс для DMR (по умолчанию `0.0.0.0`);
|
||||||
|
- `-p, --port` — UDP-порт DMR (по умолчанию `62031`);
|
||||||
|
- `--web-interface` — интерфейс API (по умолчанию `0.0.0.0`);
|
||||||
|
- `--web-port` — TCP-порт API (по умолчанию `8000`);
|
||||||
|
- `-l, --log-file` — файл лога;
|
||||||
|
- `-d, --ll-debug` — уровень логирования DEBUG вместо INFO.
|
||||||
|
|
||||||
### Run
|
Настройки в коде `localmaster.py` → `DMRMasterLocal.config()`:
|
||||||
```
|
- политика доступа: сейчас активна `AllowAllPeerAuth()` — **подключиться может любой peer ID без пароля**; закомментирована строка с `ListPeerAuth({1: 'pass1', 2: ''})` — вариант со списком разрешённых ID и паролей;
|
||||||
$ . venv/bin/activate
|
- `self.register_app(ParrotApp(9990))` — ID «попугая»; у `ParrotApp` также есть параметры `repeat_delay` (5 с) и прочие, задаваемые при создании.
|
||||||
$ python localmaster.py
|
|
||||||
```
|
|
||||||
`Ctrl+C` to break and stop.
|
|
||||||
|
|
||||||
The running server listens for `62031/udp` as DMR service (may be changed with `--port` command line argument)
|
Паролей и токенов в репозитории нет: `pass1` в закомментированной строке — заглушка из примера. Реальные пароли пиров при вводе в эксплуатацию следует держать вне репозитория (см. `.env`/локальный незакоммиченный конфиг), тем более что `localmaster.py` здесь отслеживается git.
|
||||||
and exposes http API/dashboard on `8000/tcp` (may be changed with `--web-port` command line argument):
|
|
||||||
- API: http://YOUR-SERVER-IP:8000/api/dashboard
|
|
||||||
- Web dashboard: http://YOUR-SERVER-IP:8000/dashboard/index.html
|
|
||||||

|
|
||||||
|
|
||||||
|
## Состояние
|
||||||
|
Рабочий прототип (сам автор оригинала определяет статус как public alpha, версия 0.5, «не использовать в проде, интерфейсы могут меняться»). Последний коммит 2025-06-19 (собственный, переименование файла), последний коммит апстрима — 2025-06-01. Всего 17 коммитов.
|
||||||
|
|
||||||
|
## Что не доделано
|
||||||
## Roadmap
|
- Явный TODO в коде один: `dmrtools/dmrproto/lc_util.py:141` — `return None # Not supported; !!TODO: decode 7-bit` (не декодируется 7-битный Talker Alias).
|
||||||
### What is this for (general TODO)
|
- По roadmap апстрима (см. `README.upstream.md`) не реализованы: файл конфигурации и конфигурация пользователей, полноценная маршрутизация (по слотам, подписки на группы), кодирование внутренних структур DMR, датапакеты/сообщения, кодек AMBE, запись голосовых вызовов в файлы, TA внутри DMRD, регистрация абонентов и резолв ID в позывные.
|
||||||
- Private dmr network (own registration, admintool, dashboard, voice apps, etc)
|
- Собственных доработок форка нет — расхождение с оригиналом сводится к одному переименованию, поэтому обновление апстрима должно проходить без конфликтов, кроме файла `localmaster.py`.
|
||||||
- Other dmr networks bridge (configurable group/unit routing rules, ID replacements, etc)
|
- `localmaster.py` числится в `.gitignore`, но при этом отслеживается — при правке локальных настроек их легко закоммитить случайно.
|
||||||
- Bridge/proxy with packet modification (substitute IDs, add TA, etc..)
|
|
||||||
- Voice robots interface at packet level (parrot for group and unit cals, recording/playback as prewritten packets by events)
|
|
||||||
- Encoding and decoding of AMBE (allows to build advanced voice services, like voice time, agenda, etc)
|
|
||||||
- Voice call history dump (ambe files or decoded)
|
|
||||||
|
|
||||||
|
|
||||||
### Features & TODO
|
|
||||||
- ✔️ basic apps support
|
|
||||||
- ✔️ parrot
|
|
||||||
- ✔️ password check
|
|
||||||
- ✔️ fastapi api
|
|
||||||
- ✔️ web dashboard
|
|
||||||
- ✔️ unit call routing
|
|
||||||
- ✔️ allow single peer id check
|
|
||||||
- ✔️ TA support (DMRA packet)
|
|
||||||
- ✔️ dmr internal structure decoding (get LC, voice data)
|
|
||||||
- 🥕 routing (1 timeslot == 1 routing entity)
|
|
||||||
- 🥕 only one call per ts for peer (per routing entity)
|
|
||||||
- 🥕 dmr internal structure encoding (set LC, generate voice data)
|
|
||||||
- 🥕 apps unit call routing (routing entity for app)
|
|
||||||
- 🥕 configuration
|
|
||||||
- 🥕 users configuration (allowed id and passes per id)
|
|
||||||
- 🥕 resolve id to callsigns
|
|
||||||
- 🥕 routing 2: group subscriptions
|
|
||||||
- 🥕 data calls (messages)
|
|
||||||
- 🥕 ambe decode/encode
|
|
||||||
- 🥕 log voice calls as files
|
|
||||||
- 🥕 TA support 2 (inside DMRD packets)
|
|
||||||
- 🥕 registration
|
|
||||||
- 🥕 update radiod list and resolve
|
|
||||||
|
|
||||||
## Sources
|
|
||||||
- ETSI TS 102 361-1 V1.2.1 (2006-01)
|
|
||||||
Technical Specification
|
|
||||||
Electromagnetic compatibility
|
|
||||||
and Radio spectrum Matters (ERM);
|
|
||||||
Digital Mobile Radio (DMR) Systems;
|
|
||||||
Part 1: DMR Air Interface (AI) protocol
|
|
||||||
https://www.etsi.org/deliver/etsi_ts/102300_102399/10236101/01.02.01_60/ts_10236101v010201p.pdf
|
|
||||||
|
|
||||||
- ETSI TS 102 361-2 V2.3.1 (2016-02)
|
|
||||||
Electromagnetic compatibility
|
|
||||||
and Radio spectrum Matters (ERM);
|
|
||||||
Digital Mobile Radio (DMR) Systems;
|
|
||||||
Part 2: DMR voice and generic services and facilities
|
|
||||||
https://www.etsi.org/deliver/etsi_ts/102300_102399/10236102/02.03.01_60/ts_10236102v020301p.pdf
|
|
||||||
|
|
||||||
- MMDVMHost by Jonathan Naylor, G4KLX
|
|
||||||
https://github.com/g4klx/MMDVMHost
|
|
||||||
|
|
||||||
- HBLink3 by Cortney T. Buffington, N0MJS
|
|
||||||
https://github.com/n0mjs710/hblink3
|
|
||||||
|
|
||||||
- IPSC Protocol Specs for homebrew DMR repeater by DL5DI, G4KLX, DG1HT 2015 (partially obsolete)
|
|
||||||
https://wiki.brandmeister.network/images/5/54/DMRplus_IPSC_Protocol_for_HB_repeater.pdf
|
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# 0DMRMaster
|
||||||
|
Private DMR master server. Version 0.5.
|
||||||
|
Copyright ©2025 Alexander Mokrov, UR6LKW.
|
||||||
|
|
||||||
|
This project is currently in public alpha and is under active development.
|
||||||
|
Don't use it in production environment, interfaces may change.
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This project contains:
|
||||||
|
1. An implementation of homebrew dmr protocol (which is used by brandmeister and hblink). Not yet complete, but sufficient for #2 and #3.
|
||||||
|
1. Decoding UDP proxy
|
||||||
|
1. Basic private dmr master server
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
1. Check basic requirements:
|
||||||
|
- Linux or Windows
|
||||||
|
- Python 3.11+
|
||||||
|
1. Clone/download the repo.
|
||||||
|
1. Create environment and install requirements (linux example):
|
||||||
|
```
|
||||||
|
$ python -m venv venv
|
||||||
|
$ . venv/bin/activate
|
||||||
|
$ python -m pip install --upgrade pip
|
||||||
|
$ pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
Copy `localmaster_EXAMPLE.py` to `localmaster.py` and edit.
|
||||||
|
|
||||||
|
### Run
|
||||||
|
```
|
||||||
|
$ . venv/bin/activate
|
||||||
|
$ python localmaster.py
|
||||||
|
```
|
||||||
|
`Ctrl+C` to break and stop.
|
||||||
|
|
||||||
|
The running server listens for `62031/udp` as DMR service (may be changed with `--port` command line argument)
|
||||||
|
and exposes http API/dashboard on `8000/tcp` (may be changed with `--web-port` command line argument):
|
||||||
|
- API: http://YOUR-SERVER-IP:8000/api/dashboard
|
||||||
|
- Web dashboard: http://YOUR-SERVER-IP:8000/dashboard/index.html
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
### What is this for (general TODO)
|
||||||
|
- Private dmr network (own registration, admintool, dashboard, voice apps, etc)
|
||||||
|
- Other dmr networks bridge (configurable group/unit routing rules, ID replacements, etc)
|
||||||
|
- Bridge/proxy with packet modification (substitute IDs, add TA, etc..)
|
||||||
|
- Voice robots interface at packet level (parrot for group and unit cals, recording/playback as prewritten packets by events)
|
||||||
|
- Encoding and decoding of AMBE (allows to build advanced voice services, like voice time, agenda, etc)
|
||||||
|
- Voice call history dump (ambe files or decoded)
|
||||||
|
|
||||||
|
|
||||||
|
### Features & TODO
|
||||||
|
- ✔️ basic apps support
|
||||||
|
- ✔️ parrot
|
||||||
|
- ✔️ password check
|
||||||
|
- ✔️ fastapi api
|
||||||
|
- ✔️ web dashboard
|
||||||
|
- ✔️ unit call routing
|
||||||
|
- ✔️ allow single peer id check
|
||||||
|
- ✔️ TA support (DMRA packet)
|
||||||
|
- ✔️ dmr internal structure decoding (get LC, voice data)
|
||||||
|
- 🥕 routing (1 timeslot == 1 routing entity)
|
||||||
|
- 🥕 only one call per ts for peer (per routing entity)
|
||||||
|
- 🥕 dmr internal structure encoding (set LC, generate voice data)
|
||||||
|
- 🥕 apps unit call routing (routing entity for app)
|
||||||
|
- 🥕 configuration
|
||||||
|
- 🥕 users configuration (allowed id and passes per id)
|
||||||
|
- 🥕 resolve id to callsigns
|
||||||
|
- 🥕 routing 2: group subscriptions
|
||||||
|
- 🥕 data calls (messages)
|
||||||
|
- 🥕 ambe decode/encode
|
||||||
|
- 🥕 log voice calls as files
|
||||||
|
- 🥕 TA support 2 (inside DMRD packets)
|
||||||
|
- 🥕 registration
|
||||||
|
- 🥕 update radiod list and resolve
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- ETSI TS 102 361-1 V1.2.1 (2006-01)
|
||||||
|
Technical Specification
|
||||||
|
Electromagnetic compatibility
|
||||||
|
and Radio spectrum Matters (ERM);
|
||||||
|
Digital Mobile Radio (DMR) Systems;
|
||||||
|
Part 1: DMR Air Interface (AI) protocol
|
||||||
|
https://www.etsi.org/deliver/etsi_ts/102300_102399/10236101/01.02.01_60/ts_10236101v010201p.pdf
|
||||||
|
|
||||||
|
- ETSI TS 102 361-2 V2.3.1 (2016-02)
|
||||||
|
Electromagnetic compatibility
|
||||||
|
and Radio spectrum Matters (ERM);
|
||||||
|
Digital Mobile Radio (DMR) Systems;
|
||||||
|
Part 2: DMR voice and generic services and facilities
|
||||||
|
https://www.etsi.org/deliver/etsi_ts/102300_102399/10236102/02.03.01_60/ts_10236102v020301p.pdf
|
||||||
|
|
||||||
|
- MMDVMHost by Jonathan Naylor, G4KLX
|
||||||
|
https://github.com/g4klx/MMDVMHost
|
||||||
|
|
||||||
|
- HBLink3 by Cortney T. Buffington, N0MJS
|
||||||
|
https://github.com/n0mjs710/hblink3
|
||||||
|
|
||||||
|
- IPSC Protocol Specs for homebrew DMR repeater by DL5DI, G4KLX, DG1HT 2015 (partially obsolete)
|
||||||
|
https://wiki.brandmeister.network/images/5/54/DMRplus_IPSC_Protocol_for_HB_repeater.pdf
|
||||||
Ссылка в новой задаче
Block a user