/** * @file serial.proto * @brief Протокол обмена между GUI‑клиентом и backend‑службой * для работы с последовательным (UART/RS‑232/USB‑CDC) портом. * * Протокол построен на базе **Protocol Buffers 3** и **gRPC**. * Он покрывает все типичные задачи: * - перечисление доступных портов; * - открытие/закрытие порта с полным набором параметров; * - отправку и приём произвольных пакетов; * - ведение журнала (лог‑стрим) всех переданных/полученных байтов * – удобно для отладки и верификации протокола. * * Файл снабжён Doxygen‑комментариями, поэтому из него можно * автоматически получить красивую HTML‑/PDF‑документацию. */ syntax = "proto3"; package serial; /* -------------------------------------------------------------------------- */ /* Enums – вспомогательные типы */ /* -------------------------------------------------------------------------- */ /** * @enum Parity * @brief Возможные варианты чётности (parity) при работе с UART. * * Имена полностью совпадают с теми, что использует библиотека **pyserial** * (и, в принципе, большинство C/C++‑библиотек для последовательных портов). */ enum Parity { PARITY_NONE = 0; /// Без чётности. PARITY_EVEN = 1; /// Чётность чётных битов. PARITY_ODD = 2; /// Чётность нечётных битов. PARITY_MARK = 3; /// Маркер (всегда 1). PARITY_SPACE= 4; /// Пробел (всегда 0). } /** * @enum StopBits * @brief Конфигурация стоп‑битов. * * Значения соответствуют типичным настройкам UART‑контроллера. */ enum StopBits { STOPBITS_ONE = 0; /// Один стоп‑бит. STOPBITS_ONE_POINT_FIVE = 1; /// Полтора стоп‑бита (реже используется). STOPBITS_TWO = 2; /// Два стоп‑бита. } /** * @enum StatusCode * @brief Универсальный набор кодов возврата для большинства RPC‑методов. * * При необходимости можно добавить новые коды, но текущего набора достаточно * для базовых сценариев. */ enum StatusCode { OK = 0; /// Операция выполнена успешно. INVALID_ARGUMENT = 1; /// Переданы некорректные аргументы (например, отрицательная скорость). NOT_FOUND = 2; /// Запрашиваемый объект (порт, файл и т.п.) не найден. INTERNAL_ERROR = 3; /// Внутренняя ошибка сервера (исключение, недоступный ресурс). NOT_CONNECTED = 4; /// Операция невозможна, т.к. порт не открыт. } /* -------------------------------------------------------------------------- */ /* Сообщения – описание данных, передаваемых по gRPC */ /* -------------------------------------------------------------------------- */ /** * @message SerialDevice * @brief Информация об одном последовательном порте, доступном в системе. * * @param port_name Системное имя порта (например, «COM3», «/dev/ttyUSB0»). * @param description Человекочитаемое описание, если ОС его предоставляет. * @param hardware_id Строка‑идентификатор устройства (VID/PID и т.п.). */ message SerialDevice { string port_name = 1; string description = 2; string hardware_id = 3; } /** * @message SerialConfig * @brief Полный набор параметров, необходимый для открытия последовательного порта. * * @param port_name Должно совпадать с `SerialDevice.port_name`. * @param baud_rate Скорость в бодах (например, 9600, 115200 …). * @param data_bits Количество битов данных (5‑8, обычно 8). * @param parity Чётность (см. enum @ref Parity). * @param stop_bits Стоп‑биты (см. enum @ref StopBits). * @param packet_size Фиксированный размер полезной нагрузки пакета. * 0 → размер произвольный (по умолчанию). */ message SerialConfig { string port_name = 1; uint32 baud_rate = 2; uint32 data_bits = 3; Parity parity = 4; StopBits stop_bits = 5; uint32 packet_size = 6; } /** * @message ConfigResponse * @brief Ответ на запрос `Open`/`Close`. Содержит статус операции и, * при ошибке, человекочитаемое сообщение. * * @param status Код статуса (см. enum @ref StatusCode). * @param error Текстовое пояснение, заполнено только если `status != OK`. */ message ConfigResponse { StatusCode status = 1; string error = 2; } /** * @message Packet * @brief Описание логической "пакетной" единицы, которую GUI отправляет * на backend, а backend – в последовательный порт. * * Полезная нагрузка (`payload`) передаётся «как есть» (raw‑bytes). * * @param seq_id Последовательный номер пакета, генерируется клиентом. * Удобен для отладки и согласования запрос‑ответ. * @param payload Бинарные данные, которые действительно окажутся на линии. * @param tags Необязательная карта «ключ → значение», используемая * только внутри программы (не попадает в кадр UART). */ message Packet { uint64 seq_id = 1; bytes payload = 2; map tags = 3; } /** * @message SendResponse * @brief Ответ на RPC `SendPacket`. Содержит статус, сообщение об ошибке и * «эхо‑идентификатор», позволяющий клиенту убедиться, что ответ * относится к конкретному запросу. * * @param status Код статуса (см. enum @ref StatusCode). * @param error Текстовое описание ошибки (если есть). * @param echo_seq_id Идентификатор пакета, пришедший в запросе. */ message SendResponse { StatusCode status = 1; string error = 2; uint64 echo_seq_id = 3; } /** * @message SerialLogEntry * @brief Описание одного события (TX или RX) на уровне сырых байтов. * * Это «протокол‑верификация»: каждая запись сохраняется в журнал * и может быть передана клиенту в реальном времени. * * @param dir Направление трафика (TX – передача, RX – приём). * @param timestamp Время события в миллисекундах с начала эпохи Unix. * @param raw_data Точные байты, полученные/отправленные в этом событии. * @param note Необязательная строка‑комментарий (например, * «checksum ok», «frame start», …). */ message SerialLogEntry { /** @brief Направление трафика. */ enum Direction { /** @brief Пакет был отправлен в порт. */ TX = 0; /** @brief Пакет был получен из порта. */ RX = 1; } Direction dir = 1; uint64 timestamp = 2; bytes raw_data = 3; string note = 4; } /** * @message LogStreamRequest * @brief Параметры подписки на поток журнала. * * @param from_start Если true – клиент получает *все* накопленные записи, * иначе – только новые, появившиеся после установления * соединения. */ message LogStreamRequest { bool from_start = 1; } /** * @message DeviceList * @brief Обёртка, возвращающая список найденных последовательных портов. * * @param devices Список `SerialDevice`. */ message DeviceList { repeated SerialDevice devices = 1; } /* -------------------------------------------------------------------------- */ /* Service definition – набор RPC‑методов, которые реализует backend */ /* -------------------------------------------------------------------------- */ /** * @service SerialService * @brief gRPC‑сервис, предоставляющий весь функционал работы с * последовательным портом и журналированием. * * Каждый метод описан ниже, вместе с его параметрами и возвращаемыми * типами. */ service SerialService { // ---------------------------------------------------------------------- // Device discovery // ---------------------------------------------------------------------- /** * @brief Возвращает список всех последовательных портов, обнаруженных в системе. * * @param request Пустое сообщение (`google.protobuf.Empty`). * @return `DeviceList` – массив `SerialDevice`. */ rpc ListDevices (google.protobuf.Empty) returns (DeviceList); // ---------------------------------------------------------------------- // Connection handling // ---------------------------------------------------------------------- /** * @brief Открывает (или переоткрывает) последовательный порт с указанными * параметрами. * * @param cfg Полный набор параметров соединения (`SerialConfig`). * @return `ConfigResponse` – статус операции. */ rpc Open (SerialConfig) returns (ConfigResponse); /** * @brief Закрывает текущий открытый порт (если он был открыт). * * @param request Пустое сообщение. * @return `ConfigResponse` – статус операции. */ rpc Close (google.protobuf.Empty) returns (ConfigResponse); /** * @brief Возвращает конфигурацию, с которой в данный момент открыт порт. * * Если порт закрыт, возвращается пустой `SerialConfig`. * * @param request Пустое сообщение. * @return `SerialConfig`. */ rpc GetCurrentConfig (google.protobuf.Empty) returns (SerialConfig); // ---------------------------------------------------------------------- // Packet transmission // ---------------------------------------------------------------------- /** * @brief Отправка одного пакета в открытый последовательный порт. * * Если в `SerialConfig.packet_size` задан фиксированный размер, то * длина `payload` должна строго соответствовать этому размеру. * * @param pkt Пакет для отправки (`Packet`). * @return `SendResponse` – результат записи в порт. */ rpc SendPacket (Packet) returns (SendResponse); /** * @brief Получить один пакет из входящего буфера. * * Если буфер пуст, сервер возвращает gRPC‑ошибку `NOT_FOUND`. * * @param request Пустое сообщение. * @return `Packet` (или ошибка). */ rpc ReceivePacket (google.protobuf.Empty) returns (Packet); // ---------------------------------------------------------------------- // Logging / protocol verification // ---------------------------------------------------------------------- /** * @brief Прямо вставить произвольную запись в журнал. * * Полезно для отладки: можно «симулировать» приходящие данные, * не взаимодействуя с реальным оборудованием. * * @param entry Запись журнала (`SerialLogEntry`). * @return Пустое сообщение (`google.protobuf.Empty`). */ rpc LogRaw (SerialLogEntry) returns (google.protobuf.Empty); /** * @brief Подписка на поток всех событий журнала (TX и RX). * * Поток остаётся открытым до тех пор, пока клиент не отменит RPC. * * @param req Параметры подписки (`LogStreamRequest`). * @return Поток `SerialLogEntry`. */ rpc StreamLog (LogStreamRequest) returns (stream SerialLogEntry); }