
## Описание протокола CLI (command line interface)

### 1. Назначение и требования

1.1 Назначение

Протокол предназначен для тестирования и диагностики встроенного ПО устройств, подключенных к компьютеру (ПК) через интерфейс UART (COM-порт). Компьютер выступает в роли хоста (мастера), а устройства в роли подчиненных. 

Параметры интерфейса:
- тип: точка-точка или звезда;
- скорость: 115200 бод;
- четность: нет;
- стоп.бит: 1; 
 
1.2 Функциональные требования

| ID  | Требование |
|-----|-----|
| F1 | Мастер должен поддерживать одновременную работу с одним или несколькими устройствами |
| F2 | Устройство должно поддерживать одновременную работу только с одним мастером |
| F3 | Устройства должны ожидать команды от мастера и отправлять ответ (со статусом выполнения или с данными) |
| F4 | Соединение с устройством должно открываться по паролю (опицонально) |
| F5 | Протокол обмена должен быть текстовым (ASCII), с возможностью расширения диапазона команд (в зависимости от специфики устройств) |
| F6 | Протокол должен иметь защиту от неправильного закрытия соединения. Возможные случаи: нет обмена в течение 20с, обрыв сообщения |
| F7 | Размер поля данных для команды или ответа должен быть не более 64 байт  |
| F8 | -  |



### 2. Обзор протокола

Особенности:
- команда кодируется заглавной буквой, ответ на команду строчной буквой;
- все данные передаются в шестнадцатеричном формате (HEX).
- команды завершаются символом carriage return 0x0d (\r); 

| Код команды (ASCII) | Размер данных (в байтах) | Описание |
|---|--|--|
| T[xx] | 1-64 | Отправка команды\данных xx (от 00 до FF) |
| t[xx] | 1-64 | Ответ на команду xx |
| e[xx] | 1    | Ошибка команды xx |
|       |      |  |


Коды ошибок:
| Код (hex) | Описание |
|-----|----------|
| 00  | Нет ошибки |
| 01  | Неизвестная команда |
| 02  | Неверный формат или значение аргумента |
| 03  | Внутренняя ошибка устройства |


Примеры обмена:

ПК -> : T01\r             (открытие соединения);
Устр->: t00\r             (ответ: ОК);

ПК -> : T051234\r        (команда 0x05, аргумент 0x1234);
Устр->: e0502\r          (ответ: ошибка 0х02 на команду 0x05);


### 3. Описание команд

Коды команд от 0 до 31 выделены под базовые для любого устройства команды. Коды от 32 до 255 под специфичные команды, они не будут описаны в данном документе.

| ID | Команда | Формат | Ответ | Описание |   
|-----|-----|-----|-----|-----| 
| 0x00 | T00 | T00[PWD]\r | t00\r | Открыть соединение (пароль опционально) |  
| 0x01 | T01 | T01\r | t01\r | Закрыть соединение |  
| 0x02 | T02 | T02\r | t02\r | Проверка соединения (ping) |  
| 0x0A | T0A | T0A\r | t0A[данные]\r | Информация об устройстве |  
| 0x14 | T14 | T14[ADDR][SIZE]\r | t14[ДАННЫЕ]\r | Чтение памяти (T142000000004\r, T140800000010\r) |
| 0x15 | T15 | T15[ADDR][ДАННЫЕ]\r | t15\r | Запись памяти (T1520000000AABBCCDD\r, T1520000000AA\r) |
| 0xXX | - | - | - | - |


#### 3.2 Формат ответа T0A

Ответ на команду T0A содержит информацию об устройстве в следующем формате:

`
t0A[board_id][name_len][name][sn_len][sn][ver_len][ver]\r
`

| Поле | Размер | Описание |
|-----|-----|-----|
| board_id | 1 байт | Идентификатор платы (0-255) |
| name_len | 1 байт | Длина имени устройства |
| name | name_len байт | Имя устройства (ASCII) |
| sn_len | 1 байт | Длина серийного номера |
| sn | sn_len байт | Серийный номер (ASCII) |
| ver_len | 1 байт | Длина версии ПО |
| ver | ver_len байт | Версия ПО (ASCII) |

#### 3.3 Формат команд чтения/записи памяти
T14 – чтение памяти

- ADDR – 4 байта (8 HEX символов) – адрес в памяти
- SIZE – 1 байт (2 HEX символа) – количество байт для чтения (1-64)
- Допустимые адреса: Flash (0x08000000-0x08200000), SRAM (0x20000000-0x20020000)

T15 – запись памяти

- ADDR – 4 байта (8 HEX символов) – адрес в памяти
- ДАННЫЕ – 1-64 байта (2-128 HEX символов) – данные для записи
- Запись возможна только в SRAM (0x20000000-0x20020000)

#### 3.3 Рекомендуемые команды для диагностики

Для тестирования и поиска неисправностей рекомендуется добавить следующие команды:

| Код | Команда | Формат | Ответ | Назначение | Что проверяет |  
|-----|-----|-----|-----|-----|-----|  
| 0x03 | T03 | T03\r | t03\r | Сброс устройства | Перезагрузка МК, корректность инициализации после сброса |  
| 0x04 | T04 | T04\r | t04[STATUS]\r | Статус устройства | Флаги ошибок (1 байт: бит0-аппаратная, бит1-программная, бит2-конфигурация) |  
| 0x05 | T05 | T05\r | t05[RESULT]\r | Self-test | RAM (чтение/запись), Flash (CRC), периферия (регистры) |  
| 0x06 | T06 | T06[PIN]\r | t06[VALUE]\r | Чтение GPIO | Состояние указанного пина (0/1) или всех пинов порта |  
| 0x07 | T07 | T07[PIN][VALUE]\r | t07\r | Запись GPIO | Управление выходом (установка 0 или 1), проверка цепи |  
| 0x08 | T08 | T08[ADDR]\r | t08[VALUE]\r | Чтение регистра ПЛИС | fpga_read_reg() – связь с ПЛИС, целостность регистров |  
| 0x09 | T09 | T09[ADDR][VALUE]\r | t09\r | Запись регистра ПЛИС | fpga_write_reg() – конфигурация ПЛИС, проверка записи |  
| 0x10 | T10 | T10\r | t10[TEMP]\r | Чтение температуры | Встроенный датчик МК, корректность АЦП |  
| 0x11 | T11 | T11\r | t11[VDD][VBAT]\r  | Чтение напряжения | VDD (питание), VBAT (батарея), корректность АЦП |  
| 0x12 | T12 | T12[DATA]\r | t12\r | Логирование в файл | Запись данных в Flash (циклический буфер для отладки) |  
| 0x13 | T13 | T13\r | t13[VERSION]\r | Версия загрузчика | Bootloader version (отдельно от прошивки МК) |

### 4. API библиотеки для ПК

```
class CLIProtocol:
    def __init__(self, port: str, baudrate: int = 115200):
        """Инициализация"""
        self.port = port
        self.baudrate = baudrate
    
    def open(self) -> bool:
        """Открыть COM-порт"""
        pass
    
    def close(self) -> None:
        """Закрыть COM-порт"""
        pass
    
    def send_cmd(self, cmd: int, data: bytes = b'') -> bytes:
        """Отправить команду и получить ответ"""
        pass
    
    def get_error_string(self, err_code: int) -> str:
        """Получить текстовое описание ошибки"""
        errors = {
            0x00: "Нет ошибки",
            0x01: "Неизвестная команда",
            0x02: "Неверный формат или значение аргумента",
            0x03: "Внутренняя ошибка устройства"
        }
        return errors.get(err_code, "Неизвестная ошибка")
    
    def open_connection(self, password: str = "") -> bool:
        """Открыть соединение (T00)"""
        pass
    
    def close_connection(self) -> bool:
        """Закрыть соединение (T01)"""
        pass
    
    def ping(self) -> bool:
        """Проверить соединение (T02)"""
        pass
    
    def get_device_info(self) -> dict:
        """Получить информацию об устройстве (T0A)"""
        pass
    
    def read_memory(self, addr: int, size: int) -> bytes:
        """Чтение памяти (T14)"""
        pass
    
    def write_memory(self, addr: int, data: bytes) -> bool:
        """Запись памяти (T15)"""
        pass
```

