# bootloader: target test docs
This commit is contained in:
parent
6a643ae790
commit
db2c573642
7 changed files with 305 additions and 4 deletions
59
tests/target/hil_button/README.md
Normal file
59
tests/target/hil_button/README.md
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
# test_hil_button
|
||||||
|
|
||||||
|
## Модуль под тестом
|
||||||
|
|
||||||
|
`bsp/button` — HIL-прошивка `test_hil_button` (`main.c`), поднимающая CLI
|
||||||
|
(`READ`, `STATE`, `POLL`, `EVENT_P`, `EVENT_R`) поверх двух физических
|
||||||
|
кнопок на плате таргета (`TactBut1`, `TactBut2`). Фоновый debounce-poll
|
||||||
|
крутится в главном цикле каждые 5 мс. Прошивка не содержит проверок — она
|
||||||
|
исполняет команды; assert'ы находятся в pytest на хосте.
|
||||||
|
|
||||||
|
## Категория
|
||||||
|
|
||||||
|
HIL, интерактивный — стенд M5StampPLC для стимула не используется, кнопки
|
||||||
|
нажимает оператор вручную по подсказкам в консоли (`@pytest.mark.interactive`,
|
||||||
|
запуск с `-s`). M5StampPLC по-прежнему нужен для управления питанием
|
||||||
|
таргета (RLY1).
|
||||||
|
|
||||||
|
## Моки
|
||||||
|
|
||||||
|
Программных моков и стенда-стимулятора нет — тестируется физическое
|
||||||
|
нажатие реальных кнопок человеком-оператором. Роль «стимула» играет
|
||||||
|
оператор: хелпер `_operator_prompt()` печатает инструкцию и блокируется на
|
||||||
|
`input()` до нажатия Enter, после чего выдерживается пауза
|
||||||
|
`DEBOUNCE_SETTLE_S` (100 мс) на срабатывание дебаунса. Все проверки — в
|
||||||
|
`tools/hil/04_test_button.py`.
|
||||||
|
|
||||||
|
## Что проверяется
|
||||||
|
|
||||||
|
- Канал host↔target работает (`PING`).
|
||||||
|
- Сырое чтение (`READ`) в состоянии покоя и при нажатии/отпускании для
|
||||||
|
обеих кнопок.
|
||||||
|
- Debounce-события нажатия (`EVENT_P`) и отпускания (`EVENT_R`) и их
|
||||||
|
одноразовое потребление (повторный запрос без нового действия даёт `0`).
|
||||||
|
- Стабильное состояние (`STATE`) во время удержания кнопки и после
|
||||||
|
отпускания.
|
||||||
|
- Независимость кнопок — нажата только одна, вторая остаётся отпущенной.
|
||||||
|
|
||||||
|
## Гарантии
|
||||||
|
|
||||||
|
- Физическое нажатие/отпускание кнопки надёжно регистрируется как в
|
||||||
|
сыром чтении (`READ`), так и в дебаунсированном состоянии (`STATE`) и в
|
||||||
|
одноразовых событиях (`EVENT_P`/`EVENT_R`).
|
||||||
|
- Кнопки физически независимы — нажатие одной не влияет на показания
|
||||||
|
другой.
|
||||||
|
- Задержки в тесте (100 мс после действия оператора, фоновый poll каждые
|
||||||
|
5 мс) достаточны для гарантированного срабатывания дебаунса (порог 4
|
||||||
|
стабильных сэмпла).
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just build::build-hil # в devcontainer: собрать HIL-прошивки
|
||||||
|
just host::hil-button # на хосте: прошить и прогнать тест (интерактивно)
|
||||||
|
# или все интерактивные тесты сразу:
|
||||||
|
just host::hil-run-interactive
|
||||||
|
```
|
||||||
|
|
||||||
|
Тест интерактивный — требует присутствия оператора у стенда для нажатия
|
||||||
|
кнопок по подсказкам в терминале.
|
||||||
67
tests/target/hil_can/README.md
Normal file
67
tests/target/hil_can/README.md
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# test_hil_can
|
||||||
|
|
||||||
|
## Модуль под тестом
|
||||||
|
|
||||||
|
`bsp/can` — HIL-прошивка `test_hil_can` (`main.c`), поднимающая CLI
|
||||||
|
(`CAN_SEND`, `CAN_RECV`, `CAN_FILTER`, `CAN_ACCEPT_ALL`, `CAN_RX_EVENTS`,
|
||||||
|
`CAN_LAST_RX`, `CAN_RESET_EVENTS`) поверх реальной CAN-шины (трансивер
|
||||||
|
SN65HVD230D на таргете). Прошивка не содержит проверок — она исполняет
|
||||||
|
команды и передаёт/принимает фреймы на физической шине; assert'ы находятся
|
||||||
|
в pytest на хосте.
|
||||||
|
|
||||||
|
## Категория
|
||||||
|
|
||||||
|
HIL, требует стенд M5StampPLC (трансивер SIT1044) как второй узел на общей
|
||||||
|
CAN-шине 125 kbit/s. M5 также управляет питанием таргета (RLY1).
|
||||||
|
|
||||||
|
> `bsp_can_init()` вызывается с `disableSelfReception=true` — таргет не
|
||||||
|
> слышит собственные фреймы. Сценарий «таргет TX → таргет RX» без
|
||||||
|
> ретрансляции через M5 не тестируется напрямую.
|
||||||
|
|
||||||
|
## Моки
|
||||||
|
|
||||||
|
Программных моков нет — тестируется реальная передача по физической шине.
|
||||||
|
Роль второго узла играет M5StampPLC под управлением MicroPython-агента
|
||||||
|
(`tools/hil/m5/agent.py`): pytest дистанционно отправляет/принимает
|
||||||
|
CAN-фреймы через JSON-команды по USB CDC (`m5.can_send()`,
|
||||||
|
`m5.can_recv()`, фикстура `m5` в `conftest.py`). Все проверки — в
|
||||||
|
`tools/hil/03_test_can.py`.
|
||||||
|
|
||||||
|
## Что проверяется
|
||||||
|
|
||||||
|
- **Connectivity** — таргет отвечает на `PING`, M5-агент отвечает на
|
||||||
|
`ping` и сообщает `can_ok=true`.
|
||||||
|
- **M5 → таргет** — приём STD/EXT фрейма с верным ID и данными,
|
||||||
|
максимальный `DLC=8`, `DLC=0`, инкремент счётчика RX-событий на каждый
|
||||||
|
принятый фрейм.
|
||||||
|
- **Таргет → M5** — отправка STD/EXT фрейма, граничные ID (`0x000`,
|
||||||
|
`0x7FF`, `0x1FFFFFFF`), целостность всех 8 байт данных без искажений.
|
||||||
|
- **Фильтрация** — `CAN_ACCEPT_ALL` принимает любой ID; точная маска
|
||||||
|
(`0x7FF`) пропускает только совпадающий ID и блокирует остальные; маска
|
||||||
|
по группе старших бит (`0x7F0`) пропускает всю группу; повторный
|
||||||
|
`CAN_ACCEPT_ALL` снимает ранее установленный фильтр.
|
||||||
|
- **Типы фреймов** — STD и EXT не путаются друг с другом ни в одну, ни в
|
||||||
|
другую сторону, включая граничные значения ID.
|
||||||
|
|
||||||
|
## Гарантии
|
||||||
|
|
||||||
|
- Фреймы передаются по физической шине в обе стороны без потери и
|
||||||
|
искажения ID/данных, включая граничные STD (`0x7FF`) и EXT
|
||||||
|
(`0x1FFFFFFF`) идентификаторы.
|
||||||
|
- Аппаратная фильтрация по ID/маске работает корректно: точное совпадение,
|
||||||
|
совпадение по группе бит, полное открытие через `accept_all`.
|
||||||
|
- Счётчик принятых фреймов увеличивается ровно на каждый физически
|
||||||
|
принятый фрейм.
|
||||||
|
- STD- и EXT-фреймы всегда различимы (`is_extended` не искажается при
|
||||||
|
передаче по шине).
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just build::build-hil # в devcontainer: собрать HIL-прошивки
|
||||||
|
just host::m5-deploy # один раз / после правок agent.py: залить агент на M5
|
||||||
|
just host::hil-can # на хосте: прошить по SWD и прогнать тест
|
||||||
|
```
|
||||||
|
|
||||||
|
Требует MicroPython v1.25 на M5StampPLC (`tools/hil/m5/firmware/v1.25/`) —
|
||||||
|
в v1.27 модуль CAN недоступен.
|
||||||
60
tests/target/hil_opto/README.md
Normal file
60
tests/target/hil_opto/README.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# test_hil_opto
|
||||||
|
|
||||||
|
## Модуль под тестом
|
||||||
|
|
||||||
|
`bsp/opto` — HIL-прошивка `test_hil_opto` (`main.c`), поднимающая CLI
|
||||||
|
(`OPTO_READ <1|2|3>`, `OPTO_EVENTS`, `OPTO_LAST_EVENT`,
|
||||||
|
`OPTO_RESET_EVENTS`) поверх трёх реальных оптоизолированных входов
|
||||||
|
(PS2801-4, active-HIGH). `bsp_opto_process()` крутится в главном цикле
|
||||||
|
каждую итерацию. Прошивка не содержит проверок — она исполняет команды и
|
||||||
|
считает callback-события; assert'ы находятся в pytest на хосте.
|
||||||
|
|
||||||
|
## Категория
|
||||||
|
|
||||||
|
HIL, требует стенд M5StampPLC — реле M5 физически замыкают/размыкают цепи
|
||||||
|
оптопар таргета (`EXT_IN1`/`EXT_IN2`/`RS_RX`, точный маппинг реле↔канал —
|
||||||
|
см. `docs/testing/hil/HIL_BENCH.md` и `tools/hil/m5/agent.py`). M5 также
|
||||||
|
управляет питанием таргета (RLY1).
|
||||||
|
|
||||||
|
## Моки
|
||||||
|
|
||||||
|
Программных моков нет — тестируется реальная электрическая цепь
|
||||||
|
оптопар. Роль стимула играет M5StampPLC под управлением MicroPython-агента
|
||||||
|
(`tools/hil/m5/agent.py`): pytest дистанционно щёлкает реле через
|
||||||
|
JSON-команды по USB CDC (`m5.opto_set(ch, bool)`, `m5.opto_all_off()`,
|
||||||
|
фикстура `m5` в `conftest.py`). Все проверки — в `tools/hil/02_test_opto.py`.
|
||||||
|
|
||||||
|
## Что проверяется
|
||||||
|
|
||||||
|
- **Connectivity** — таргет отвечает на `PING`, M5-агент отвечает на
|
||||||
|
`ping`.
|
||||||
|
- **Состояние по умолчанию** — все три канала `INACTIVE` без внешнего
|
||||||
|
воздействия.
|
||||||
|
- **Активация/деактивация** каждого канала по отдельности (реле ON →
|
||||||
|
`ACTIVE`, реле OFF → `INACTIVE`) и **изоляция** — активация одного канала
|
||||||
|
не меняет состояние остальных.
|
||||||
|
- **Callback-события** — включение/выключение реле генерирует минимум одно
|
||||||
|
событие с правильным каналом и состоянием (проверяет цепочку
|
||||||
|
ISR → debounce → `bsp_opto_process()` → callback), `OPTO_RESET_EVENTS`
|
||||||
|
обнуляет счётчик, `OPTO_LAST_EVENT` сообщает верный канал при
|
||||||
|
срабатывании нескольких каналов подряд.
|
||||||
|
|
||||||
|
## Гарантии
|
||||||
|
|
||||||
|
- Физическое замыкание/размыкание оптопары надёжно регистрируется через
|
||||||
|
ISR + программный debounce (10 мс) и доходит до пользовательского
|
||||||
|
callback.
|
||||||
|
- Каналы физически и логически независимы — воздействие на один не влияет
|
||||||
|
на показания и события других.
|
||||||
|
- Без внешнего воздействия состояние стабильно `INACTIVE` на всех каналах.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just build::build-hil # в devcontainer: собрать HIL-прошивки
|
||||||
|
just host::m5-deploy # один раз / после правок agent.py: залить агент на M5
|
||||||
|
just host::hil-opto # на хосте: прошить по SWD и прогнать тест
|
||||||
|
```
|
||||||
|
|
||||||
|
Требует MicroPython v1.25 на M5StampPLC (`tools/hil/m5/firmware/v1.25/`) —
|
||||||
|
в v1.27 модуль CAN недоступен и `agent.py` не стартует корректно.
|
||||||
|
|
@ -12,7 +12,9 @@
|
||||||
* OPTO_RESET_EVENTS -> OK (сбросить счётчики)
|
* OPTO_RESET_EVENTS -> OK (сбросить счётчики)
|
||||||
*
|
*
|
||||||
* Стенд:
|
* Стенд:
|
||||||
* M5StampPLC: RLY2->EXT_IN1(ch1), RLY3->EXT_IN2(ch2), RLY4->RS_RX(ch3)
|
* M5StampPLC: RLY2->RS_RX(ch3), RLY3->EXT_IN1(ch1), RLY4->EXT_IN2(ch2)
|
||||||
|
* (маппинг реле — см. _OPTO_TO_RELAY в tools/hil/m5/agent.py и
|
||||||
|
* docs/testing/hil/HIL_BENCH.md)
|
||||||
*
|
*
|
||||||
* ВАЖНО: bsp_opto_process() вызывается в каждой итерации main loop.
|
* ВАЖНО: bsp_opto_process() вызывается в каждой итерации main loop.
|
||||||
* CLI_RX_TIMEOUT=10ms для быстрого цикла обработки debounce.
|
* CLI_RX_TIMEOUT=10ms для быстрого цикла обработки debounce.
|
||||||
|
|
|
||||||
58
tests/target/hil_usb_cdc/README.md
Normal file
58
tests/target/hil_usb_cdc/README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# test_hil_usb_cdc
|
||||||
|
|
||||||
|
## Модуль под тестом
|
||||||
|
|
||||||
|
`bsp/usb_cdc` — HIL-прошивка `test_hil_usb_cdc` (`main.c`), поднимающая два
|
||||||
|
независимых канала: UART (MCU-Link VCOM) — управляющий (`PING`,
|
||||||
|
`USB_READY`), и USB CDC (порт платы таргета) — тестируемый эхо-канал:
|
||||||
|
всё, что пришло по USB CDC, отправляется обратно (`usb_cdc_echo_process()`
|
||||||
|
в главном цикле). Прошивка не содержит проверок — она исполняет команды и
|
||||||
|
эхо; assert'ы находятся в pytest на хосте.
|
||||||
|
|
||||||
|
## Категория
|
||||||
|
|
||||||
|
HIL, требует физическое USB-подключение платы таргета к хосту (порт
|
||||||
|
задаётся `HIL_USB_CDC_PORT`). M5StampPLC стенд не используется как
|
||||||
|
источник сигнала, но нужен для управления питанием таргета (RLY1).
|
||||||
|
|
||||||
|
## Моки
|
||||||
|
|
||||||
|
Программных моков нет — тестируется реальный стек USB CDC ACM (enumeration,
|
||||||
|
DTR, bulk-транзакции). Все проверки — в `tools/hil/05_test_usb_cdc.py`,
|
||||||
|
через фикстуры `conftest.py`: `uart_hil_usb_cdc` (управляющий UART, ждёт
|
||||||
|
`READY`) и `usb_cdc_port` (тестируемый CDC-порт — ждёт появления после
|
||||||
|
enumeration и выставляет DTR).
|
||||||
|
|
||||||
|
## Что проверяется
|
||||||
|
|
||||||
|
- Управляющий UART отвечает (`PING` → `PONG`), прошивка запущена.
|
||||||
|
- `USB_READY` подтверждает, что enumeration завершён и хост открыл порт
|
||||||
|
(`bsp_usb_cdc_is_ready()`).
|
||||||
|
- Echo коротких данных, данных с `\r\n` (проверка, что канал бинарный, а
|
||||||
|
не построчный), полного диапазона байт `0x00..0xFF`, 10 итераций подряд
|
||||||
|
без потерь.
|
||||||
|
- Echo на границах размера пакета: 64 байта (full-speed bulk) и 512 байт
|
||||||
|
(high-speed bulk, `BSP_USB_CDC_MAX_PACKET_SIZE`).
|
||||||
|
- Управляющий UART-канал продолжает работать после серии USB CDC операций.
|
||||||
|
|
||||||
|
## Гарантии
|
||||||
|
|
||||||
|
- USB CDC ACM успешно перечисляется, и прошивка корректно сообщает об этом
|
||||||
|
через `bsp_usb_cdc_is_ready()`.
|
||||||
|
- Эхо-канал побайтово точен для печатных, бинарных данных и данных с
|
||||||
|
управляющими символами — канал не трактуется как построчный и не режет
|
||||||
|
данные по `\r`/`\n`.
|
||||||
|
- Корректная работа сохраняется на границах размера пакета (64 и 512
|
||||||
|
байт), не только для «удобных» коротких сообщений.
|
||||||
|
- Активность на USB CDC не блокирует и не роняет параллельный
|
||||||
|
UART-канал.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just build::build-hil # в devcontainer: собрать HIL-прошивки
|
||||||
|
just host::hil-usb-cdc # на хосте: прошить по SWD и прогнать тест
|
||||||
|
```
|
||||||
|
|
||||||
|
Требует переменные окружения `HIL_USB_CDC_PORT` (порт USB CDC устройства
|
||||||
|
таргета) и опционально `HIL_USB_CDC_BAUD` (по умолчанию 115200) в `.env`.
|
||||||
54
tests/target/host_uart/README.md
Normal file
54
tests/target/host_uart/README.md
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# test_host_uart
|
||||||
|
|
||||||
|
## Модуль под тестом
|
||||||
|
|
||||||
|
`bsp/uart_host` — HIL-прошивка `test_host_uart` (`main.c`), поднимающая
|
||||||
|
текстовый CLI (`PING`, `ECHO <text>`, `UART_BUF_SIZE`) поверх реального
|
||||||
|
LPUART1 (MCU-Link VCOM). Сама прошивка не содержит проверок — она только
|
||||||
|
исполняет команды; assert'ы находятся в pytest на хосте (см. «Моки»).
|
||||||
|
|
||||||
|
## Категория
|
||||||
|
|
||||||
|
HIL (Hardware-in-the-Loop), автономный — стимул не нужен, достаточно платы
|
||||||
|
таргета и SWD/VCOM подключения через MCU-Link. M5StampPLC используется
|
||||||
|
только для управления питанием таргета (реле RLY1), не как источник
|
||||||
|
сигнала.
|
||||||
|
|
||||||
|
## Моки
|
||||||
|
|
||||||
|
Программных моков нет — тестируется реальный физический UART.
|
||||||
|
Роль «тестового окружения» играет pytest-стек в `tools/hil/`:
|
||||||
|
|
||||||
|
- `conftest.py` — фикстура `loaded_host_uart` грузит ELF на таргет по SWD
|
||||||
|
через pyOCD, фикстура `uart` открывает VCOM-порт и ждёт строку `READY` от
|
||||||
|
прошивки, хелпер `uart_cmd()` шлёт команду и читает одну строку ответа.
|
||||||
|
- `01_test_uart.py` — все проверки (`assert`) и сценарии.
|
||||||
|
|
||||||
|
## Что проверяется
|
||||||
|
|
||||||
|
- Канал host↔target работает (`PING` → `PONG`), в том числе 10 раз подряд
|
||||||
|
без потерь и зависаний.
|
||||||
|
- `ECHO` не искажает данные: простой текст, текст с пробелами, цифры,
|
||||||
|
payload, близкий к `CLI_LINE_MAX`.
|
||||||
|
- `UART_BUF_SIZE` возвращает значение, совпадающее с фактически
|
||||||
|
скомпилированным `BSP_UART_HOST_RX_BUFFER_SIZE` (512, задаётся через
|
||||||
|
`target_compile_definitions` в CMake).
|
||||||
|
- Неизвестная команда даёт `ERR_UNKNOWN`, после чего канал продолжает
|
||||||
|
работать (`PING` снова отвечает `PONG`).
|
||||||
|
|
||||||
|
## Гарантии
|
||||||
|
|
||||||
|
- Канал host↔target не виснет ни после серии команд, ни после неизвестной
|
||||||
|
команды.
|
||||||
|
- `ECHO` передаёт полезную нагрузку побайтово точно, без обрезки, вплоть до
|
||||||
|
почти полного `CLI_LINE_MAX`.
|
||||||
|
- Размер RX-буфера, о котором сообщает прошивка, соответствует реально
|
||||||
|
скомпилированному значению — расхождение между прошивкой и ожиданиями
|
||||||
|
хоста будет замечено.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just build::build-hil # в devcontainer: собрать HIL-прошивки
|
||||||
|
just host::hil-uart # на хосте: прошить по SWD и прогнать тест
|
||||||
|
```
|
||||||
|
|
@ -3,9 +3,10 @@ test_opto.py — HIL тест bsp_opto через M5StampPLC.
|
||||||
|
|
||||||
Стенд:
|
Стенд:
|
||||||
M5StampPLC реле → оптопары таргета (PS2801-4, active-HIGH, неинвертирующие):
|
M5StampPLC реле → оптопары таргета (PS2801-4, active-HIGH, неинвертирующие):
|
||||||
RLY2 → EXT_IN1 (ch1, BSP_OPTO_CH_IN1)
|
RLY2 → RS_RX (ch3, BSP_OPTO_CH_RS)
|
||||||
RLY3 → EXT_IN2 (ch2, BSP_OPTO_CH_IN2)
|
RLY3 → EXT_IN1 (ch1, BSP_OPTO_CH_IN1)
|
||||||
RLY4 → RS_RX (ch3, BSP_OPTO_CH_RS)
|
RLY4 → EXT_IN2 (ch2, BSP_OPTO_CH_IN2)
|
||||||
|
(маппинг реле — источник истины: _OPTO_TO_RELAY в tools/hil/m5/agent.py)
|
||||||
|
|
||||||
Цепочка фикстур (scope=module, создаются один раз на весь файл):
|
Цепочка фикстур (scope=module, создаются один раз на весь файл):
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue