# Техническая конфигурация Exchanger ## Назначение и расположение Монтажные параметры автомата хранятся отдельно от настроек владельца и не выводятся ни в одной доступной вкладке приложения. Технический специалист меняет TOML при установке или обслуживании автомата. Встроенный шаблон: ```text res://config/technical_settings.toml ``` Рабочий файл конкретного автомата: ```text user://config/technical_settings.toml ``` Для текущей Windows-сборки это обычно `%APPDATA%\Godot\app_userdata\Exchanger\config\technical_settings.toml`. Для Linux-сборки это обычно `~/.local/share/godot/app_userdata/Exchanger/config/technical_settings.toml`. При первом запуске приложение копирует встроенный шаблон в `user://config/`. Дальше рабочий файл не перезаписывается автоматически, поэтому комментарии и монтажные значения сохраняются. ## Порядок применения При старте приложение: 1. загружает обычные настройки владельца из `appsettings.json`; 2. читает и полностью проверяет `technical_settings.toml`; 3. применяет аппаратные значения и optional `[theme]` из TOML поверх обычных JSON-настроек; 4. применяет явные аргументы `--theme-dlc`, `--no-theme-dlc` и `--mock-hardware` последними; 5. загружает выбранную тему и создаёт mock- или COM-транспорт. Изменение TOML во время работы ничего не переключает. После редактирования приложение необходимо полностью перезапустить. ## Полный пример ```toml version = 1 [theme] enabled = true directory = "user://theme_dlc" file_name = "active_theme" [controller] use_mock = true port = "COM3" baud_rate = 115200 reconnect_interval_seconds = 30 handshake_timeout_ms = 2000 frame_timeout_ms = 100 max_frame_length = 1024 cashless_keep_alive_seconds = 120 [hopper_1] enabled = true stock_sensor_input = 1 stock_low_active_high = false dispense_sensor_input = 24 dispense_pulse_active_high = false [hopper_2] enabled = true stock_sensor_input = 4 stock_low_active_high = false dispense_sensor_input = 25 dispense_pulse_active_high = false [service] button_input = 8 button_active_high = false [polling] input_poll_ms = 100 stock_poll_seconds = 5 ``` ## Каталог и выбор темы Необязательный раздел `[theme]` позволяет монтажнику выбрать PCK без изменения настроек владельца: ```toml [theme] enabled = true directory = "/opt/exchanger/themes" file_name = "space-pixel" ``` Приложение загрузит `/opt/exchanger/themes/space-pixel.pck`. `directory` принимает `user://` либо абсолютный локальный путь текущей ОС; относительные пути, `res://` и сегменты `..` запрещены. `file_name` содержит только имя файла без каталога и расширения `.pck`. На Windows поддерживаются оба обычных представления: ```toml # Рекомендуемый вариант с literal-строкой: обратные слеши не экранируются. directory = 'D:\Exchanger\themes' # Либо путь с прямыми слешами. directory = "D:/Exchanger/themes" ``` Если Windows-путь записывается в двойных кавычках с обратными слешами, каждый `\` по правилам TOML необходимо удвоить: `directory = "D:\\Exchanger\\themes"`. `enabled = false` отключает внешний PCK. Раздел является авторитетным относительно полей Themes в `appsettings.json`, но разовый аргумент `--theme-dlc=<полный путь>` или `--no-theme-dlc` имеет более высокий приоритет. Старые файлы версии 1 без `[theme]` остаются совместимыми: тогда выбор темы по-прежнему берётся из `appsettings.json`. ## Основной контроллер | Параметр | Назначение | Допустимое значение | |---|---|---| | `use_mock` | Программный имитатор вместо платы | `true` или `false` | | `port` | Порт основного контроллера | Windows: `COM1`…`COM256` или `COM` для автопоиска; Linux: `/dev/ttyUSB*`, `/dev/ttyACM*`, `/dev/serial/by-id/*` или `ttyUSB`/`/dev/ttyUSB` для автопоиска | | `baud_rate` | Скорость последовательного порта | 9600, 19200, 38400, 57600, 115200, 230400, 460800 или 921600 | | `reconnect_interval_seconds` | Пауза перед повторным подключением | 1…60 с | | `handshake_timeout_ms` | Общий предел ожидания авторизации платы | 1000…60000 мс | | `frame_timeout_ms` | Ожидание продолжения неполного кадра | 10…5000 мс | | `max_frame_length` | Максимальная длина входного кадра | 2…65536 байт | | `cashless_keep_alive_seconds` | Интервал keep-alive Вендиста | 30…170 с; штатно 120 с | Первое открытие порта выполняется сразу при запуске. Если платы нет или открыть устройство не удалось, следующая попытка выполняется через `reconnect_interval_seconds`, после чего повторяется с тем же интервалом. При физическом отключении уже работавшей платы новый полный интервал отсчитывается от обнаруженного обрыва: старый дедлайн запуска не используется. Штатное значение — 30 секунд. Автоматически повторяются только подключение и авторизация; команда оплаты или выдачи после обрыва не отправляется повторно. Полное имя (`COM3`, `/dev/ttyUSB0`, `ttyUSB0` и т. п.) всегда открывается как один заданный порт. Значение `COM` включает автопоиск: на каждом начальном подключении и каждом reconnect приложение получает список доступных COM-портов, сортирует их по номеру от `COM0` и последовательно пробует до успешной авторизации. Значение `ttyUSB` (также допустимо `/dev/ttyUSB`) аналогично перебирает `/dev/ttyUSB0`, `/dev/ttyUSB1` и далее. Открытие чужого последовательного устройства или ошибка/таймаут авторизации не считаются успешным подключением: поиск продолжается со следующим номером. Безопасный шаблон содержит `use_mock = true`: простого копирования файла недостаточно для выхода на реальную плату. При вводе автомата в эксплуатацию нужно задать правильный порт, проверить остальные разделы и только затем изменить значение на `false`. Формат `port` проверяется по ОС, на которой запущено приложение. Windows-сборка с реальной платой принимает строгие имена `COM1`…`COM256` или префикс `COM`; Linux-сборка — `/dev/ttyUSB*`, `/dev/ttyACM*`, стабильные udev-ссылки `by-id`, префикс `ttyUSB` (с необязательным `/dev/`) и короткие точные имена `ttyUSB0`, `ttyUSB1` и т. д. При `use_mock = true` имя порта не используется и не проверяется, поэтому общий безопасный шаблон с `COM3` запускается и в Linux. Для Silicon Labs CP210x после подключения обычно используется: ```toml [controller] use_mock = false port = "/dev/ttyUSB0" ``` Если каталог `/dev/serial/by-id/` создан udev, предпочтительнее указать находящуюся в нём постоянную ссылку: она не меняется при перестановке USB-устройств. Отсутствие самого каталога не является ошибкой — тогда используется `/dev/ttyUSB0` или другой фактически назначенный номер. Каталог `/dev/usb/` не является заменой узла последовательного порта. ## Хопперы Разделы `hopper_1` и `hopper_2` имеют одинаковую структуру: | Параметр | Назначение | |---|---| | `enabled` | Установлен ли хоппер | | `stock_sensor_input` | Индекс входа датчика малого остатка | | `stock_low_active_high` | `true`, если высокий уровень означает «мало жетонов» | | `dispense_sensor_input` | Индекс отдельного физического датчика выдачи | | `dispense_pulse_active_high` | `true`, если высокий уровень означает импульс выдачи | Индекс входа задаётся числом 0…25. Значение `-1` означает, что отдельный физический вход не назначен. Для текущей разводки первый датчик выдачи использует `IN24`, второй — `IN25`. Обычная выдача подтверждается ответами `HOPPER1/2 OK`, а сервисный пересчёт — ответами `HOPPER1/2 PULSE=1`, поэтому физические входы не создают двойной программный учёт. По `enabled` автоматически выбирается профиль команд: | Хоппер 1 | Хоппер 2 | Профиль | |---|---|---| | включён | включён | `DualHopperAuto` — команды `30X` и `40X` | | включён | выключен | `Hopper1Auto` — команды `30X` | | выключен | включён | `Hopper2Auto` — команды `40X` | | выключен | выключен | выдача не поддерживается | У отключённого хоппера его входы принудительно становятся неактивными независимо от записанных чисел. Так узел можно временно отключить, не удаляя его монтажную схему из файла. Если включён только один хоппер, приложение работает как одноканальное: выдача, сервисный пересчёт, ручное пополнение, доступный покупателю остаток и mock-режим используют только этот хоппер. Строка и кнопки отключённого хоппера скрываются в разделе «Сервис». Его сохранённый учётный остаток не удаляется и снова станет доступен, если хоппер вернуть в конфигурацию. ## Сервисная кнопка и опрос `service.button_input` задаёт индекс сервисной кнопки, 0…25 либо `-1`, если физическая кнопка отключена. `service.button_active_high` задаёт полярность. Для текущей разводки используются `IN8` и `false`. `polling.input_poll_ms` задаёт частоту резервного чтения входов в диапазоне 50…1000 мс. `polling.stock_poll_seconds` задаёт медленный опрос запаса в диапазоне 1…60 с. ## Проверка и безопасное восстановление Все прежние разделы и поля обязательны; новый `[theme]` целиком необязателен для совместимости. Если `[theme]` присутствует, обязательны все три его поля. Приложение отклоняет файл целиком, если: - TOML имеет синтаксическую ошибку; - отсутствует поле или раздел; - версия схемы не равна 1; - значение вышло за разрешённый диапазон; - один неотрицательный индекс `IN` назначен нескольким активным функциям. - каталог темы не является `user://` или абсолютным локальным путём; - `file_name` содержит путь либо расширение. Некорректный пользовательский файл не исправляется и не перезаписывается автоматически. Приложение выдаёт предупреждение и запускается со встроенным профилем, где `use_mock = true`. Ошибочный монтажный файл поэтому не может случайно включить реальное оборудование. AES-ключ, платёжные секреты, PIN владельца, сырые команды и ответы платы в TOML не добавляются. ## Чек-лист технической настройки 1. Остановить приложение. 2. Открыть рабочий `user://config/technical_settings.toml`. 3. Проверить имя последовательного порта текущей ОС и наличие каждого хоппера. 4. Проверить `reconnect_interval_seconds = 30` либо установить другой допустимый интервал. 5. Сверить индексы и полярности подключённых входов. 6. Проверить `[theme].directory` и указать `[theme].file_name` без `.pck`. 7. Оставить `use_mock = true` для первой проверки интерфейса. 8. После проверки платы изменить `use_mock` на `false`. 9. Полностью запустить приложение заново и выполнить отдельный приёмочный прогон оборудования.