# 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 (сбросить счётчики)
|
||||
*
|
||||
* Стенд:
|
||||
* 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.
|
||||
* 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, неинвертирующие):
|
||||
RLY2 → EXT_IN1 (ch1, BSP_OPTO_CH_IN1)
|
||||
RLY3 → EXT_IN2 (ch2, BSP_OPTO_CH_IN2)
|
||||
RLY4 → RS_RX (ch3, BSP_OPTO_CH_RS)
|
||||
RLY2 → RS_RX (ch3, BSP_OPTO_CH_RS)
|
||||
RLY3 → EXT_IN1 (ch1, BSP_OPTO_CH_IN1)
|
||||
RLY4 → EXT_IN2 (ch2, BSP_OPTO_CH_IN2)
|
||||
(маппинг реле — источник истины: _OPTO_TO_RELAY в tools/hil/m5/agent.py)
|
||||
|
||||
Цепочка фикстур (scope=module, создаются один раз на весь файл):
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue