RS485
Android-модуль для аппаратных POS-терминалов и киосков самообслуживания, обеспечивающий двусторонний обмен данными по промышленной шине RS485 в режиме полудуплекса. Приложение работает как ведомое устройство на общей шине: принимает запросы от ведущего контроллера, фильтрует кадры по адресу, проверяет и формирует контрольную сумму и отвечает в реальном времени. Решение поддерживает скорости передачи вплоть до 1 Мбод, гибкую настройку адреса и канала, а также автоматически адаптируется под более чем десяток аппаратных моделей терминалов на единой кодовой базе.
Задача
Требовалось организовать устойчивую связь терминала с внешним промышленным оборудованием по двухпроводной шине RS485. Специфика задачи задавала сразу несколько жестких ограничений:
- Полудуплексный канал на одной паре проводов, где прием и передача физически разделены во времени и направление шины нужно переключать в точно выверенный момент, иначе возникают коллизии и потеря кадров.
- Бинарный протокол на базе Modbus RTU с нестандартным вариантом расчета контрольной суммы, который требовалось воспроизвести байт в байт для совместимости с ведущим контроллером.
- Работа поверх закрытого аппаратного SDK вендора с собственным набором каналов RS485 и режимов направления.
- Единый код должен корректно запускаться на широком парке устройств с разной аппаратной конфигурацией без ручной перенастройки под каждую модель.
Решение
Реализована полноценная логика ведомого устройства на шине. Входящий поток данных обрабатывается через колбэк-механизм SDK в фоновом потоке, кадры разбираются и фильтруются по заголовку и адресу устройства, после чего на валидный запрос формируется ответ.
Ключевые элементы реализации:
- Точная репликация протокольной арифметики: расчет CRC16 на рефлектированном полиноме 0xA001, последующая инверсия всех битов и перестановка байт в порядок little-endian. Это обеспечило побитовую совместимость ответа с ожиданиями ведущего контроллера.
- Синхронное управление направлением шины. Переключение в режим передачи выполняется строго на время отправки ответа, после чего канал немедленно возвращается в режим приема, что исключает наложение сигналов на полудуплексной линии.
- Адресная фильтрация на общей шине: устройство реагирует только на кадры, адресованные ему, и игнорирует чужой трафик, корректно работая в многоустройственной топологии.
- Динамическое построение списка доступных каналов RS485 из констант SDK через рефлексию, без жесткого зашивания значений в код.
- Автоматическое определение модели терминала и подстановка профиля поддерживаемой периферии, благодаря чему одна сборка покрывает весь парк устройств.
Архитектура и сложности
Самой тонкой частью стала временная диаграмма полудуплекса. Между моментом приема кадра, переключением направления и отправкой ответа нет права на ошибку: преждевременное или запоздалое переключение приводит к тому, что ведущий не видит ответ. Логика построена так, что смена режима привязана к жизненному циклу обработки конкретного кадра, а не к таймерам, что делает обмен детерминированным.
Отдельного внимания потребовала потоковая модель. Данные приходят асинхронно в фоновом потоке SDK, тогда как обновление интерфейса и индикация направления должны выполняться в UI-потоке. Разнесение этих ответственностей через корректную диспетчеризацию на главный поток убрало гонки и подвисания интерфейса при интенсивном трафике.
Управление жизненным циклом порта реализовано идемпотентно: при любой смене канала или скорости порт сначала корректно освобождается и только затем открывается заново с новыми параметрами, что исключает утечку дескрипторов и зависание шины. Поддержан полный диапазон из 11 скоростей передачи, от 9600 бод до 1 Мбод, и 8 адресов устройств на шине.
Дополнительный пласт сложности добавила работа на системном уровне с привилегированными разрешениями и закрытым вендорским SDK, поведение которого приходилось выяснять опытным путем и аккуратно оборачивать в предсказуемые сценарии.
Результат
- Стабильный двусторонний обмен по RS485 на скоростях до 1 Мбод с корректной работой протокола контрольной суммы и нулевыми коллизиями на полудуплексной линии.
- Единая кодовая база, без изменений работающая более чем на десяти моделях терминалов за счет автоматического определения аппаратной конфигурации.
- Детерминированное переключение направления шины, снявшее проблему пропадания ответов, которая характерна для наивных реализаций полудуплекса.
- Гибкая среда для интеграции и диагностики: оперативная смена адреса, канала и скорости с визуальным контролем принятых и отправленных кадров в шестнадцатеричном виде, что заметно ускорило ввод оборудования в эксплуатацию.
Стек
Java, Android SDK (minSdk 24, targetSdk 34), Gradle. Аппаратный SDK вендора POS-оборудования для доступа к RS485 и RS232. Протокол на базе Modbus RTU, расчет CRC16 (полином 0xA001). Многопоточность и колбэк-модель ввода-вывода, диспетчеризация в UI-поток, рефлексия для динамической конфигурации, работа на системном уровне с привилегированными разрешениями Android.
