will try to redo back

This commit is contained in:
Ivan I. Ovchinnikov
2026-07-28 22:28:06 +03:00
parent 8c4d40b66a
commit 20384a4dc5
4 changed files with 442 additions and 66 deletions
+305
View File
@@ -0,0 +1,305 @@
/**
* @file serial.proto
* @brief Протокол обмена между GUI‑клиентом и backend‑службой
* для работы с последовательным (UART/RS‑232/USBCDC) портом.
*
* Протокол построен на базе **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<string, string> 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);
}