# Refactoring: source code docstrings

This commit is contained in:
Dmitry Akimov 2026-07-07 12:07:15 +03:00
parent 0f54c35be6
commit 31e3237b06
21 changed files with 12 additions and 64 deletions

View file

@ -15,8 +15,6 @@
| Загрузчик (⏳ запланирован) | `firmware/bootloader/` | A/B обновление через uSD. Обновляется только через USB ROM + blhost / SWD | | Загрузчик (⏳ запланирован) | `firmware/bootloader/` | A/B обновление через uSD. Обновляется только через USB ROM + blhost / SWD |
| Production прошивка (⏳ запланирован) | `firmware/tft_app/` | Приложение с реализацией логики лифтового индикатора. Обновляется загрузчиком | | Production прошивка (⏳ запланирован) | `firmware/tft_app/` | Приложение с реализацией логики лифтового индикатора. Обновляется загрузчиком |
`bootloader`/`tft_app` пока не реализованы.
--- ---
## Инструменты (`tools/`) ## Инструменты (`tools/`)

View file

@ -161,18 +161,15 @@ static uint32_t poll_rx_mailboxes(void)
uint8_t mb_idx = RX_MB_FIRST + i; uint8_t mb_idx = RX_MB_FIRST + i;
/* Проверяем флаг готовности MB. */
uint64_t mb_flag = (uint64_t) 1U << mb_idx; uint64_t mb_flag = (uint64_t) 1U << mb_idx;
if (FLEXCAN_GetMbStatusFlags(BSP_CAN_BASE, mb_flag) == 0U) if (FLEXCAN_GetMbStatusFlags(BSP_CAN_BASE, mb_flag) == 0U)
{ {
continue; continue;
} }
/* Читаем фрейм из MB. */
flexcan_frame_t sdk_frame; flexcan_frame_t sdk_frame;
status_t sdk_status = FLEXCAN_ReadRxMb(BSP_CAN_BASE, mb_idx, &sdk_frame); status_t sdk_status = FLEXCAN_ReadRxMb(BSP_CAN_BASE, mb_idx, &sdk_frame);
/* Очищаем флаг. */
FLEXCAN_ClearMbStatusFlags(BSP_CAN_BASE, mb_flag); FLEXCAN_ClearMbStatusFlags(BSP_CAN_BASE, mb_flag);
if ((sdk_status == kStatus_Success) || (sdk_status == kStatus_FLEXCAN_RxOverflow)) if ((sdk_status == kStatus_Success) || (sdk_status == kStatus_FLEXCAN_RxOverflow))
@ -180,7 +177,6 @@ static uint32_t poll_rx_mailboxes(void)
bsp_can_frame_t bsp_frame; bsp_can_frame_t bsp_frame;
frame_from_sdk(&sdk_frame, &bsp_frame); frame_from_sdk(&sdk_frame, &bsp_frame);
/* Сериализуем фрейм побайтово в ring buffer. */
ring_buffer_write(&g_s_rx_ring, (const uint8_t *) &bsp_frame, sizeof(bsp_frame)); ring_buffer_write(&g_s_rx_ring, (const uint8_t *) &bsp_frame, sizeof(bsp_frame));
received++; received++;
} }
@ -222,16 +218,13 @@ bsp_status_t bsp_can_init(const bsp_can_config_t *p_config)
return BSP_ERR_PARAM; return BSP_ERR_PARAM;
} }
/* Если уже инициализирован — сначала деинициализируем. */
if (g_s_initialized) if (g_s_initialized)
{ {
bsp_can_deinit(); bsp_can_deinit();
} }
/* Инициализация ring buffer. */
ring_buffer_init(&g_s_rx_ring, g_s_rx_ring_storage, RX_RING_SIZE); ring_buffer_init(&g_s_rx_ring, g_s_rx_ring_storage, RX_RING_SIZE);
/* Конфигурация FlexCAN. */
flexcan_config_t flexcan_cfg; flexcan_config_t flexcan_cfg;
FLEXCAN_GetDefaultConfig(&flexcan_cfg); FLEXCAN_GetDefaultConfig(&flexcan_cfg);
@ -306,7 +299,6 @@ bsp_status_t bsp_can_set_filter(uint8_t index, uint32_t can_id, uint32_t mask, b
uint8_t mb_idx = RX_MB_FIRST + index; uint8_t mb_idx = RX_MB_FIRST + index;
/* Конфигурация RX MB. */
flexcan_rx_mb_config_t rx_mb_cfg; flexcan_rx_mb_config_t rx_mb_cfg;
rx_mb_cfg.type = kFLEXCAN_FrameTypeData; rx_mb_cfg.type = kFLEXCAN_FrameTypeData;
@ -422,14 +414,12 @@ bsp_status_t bsp_can_send(const bsp_can_frame_t *p_frame, uint32_t timeout_ms)
flexcan_frame_t sdk_frame; flexcan_frame_t sdk_frame;
frame_to_sdk(p_frame, &sdk_frame); frame_to_sdk(p_frame, &sdk_frame);
/* Записать фрейм в TX MB. */
status_t wr_status = FLEXCAN_WriteTxMb(BSP_CAN_BASE, TX_MB_IDX, &sdk_frame); status_t wr_status = FLEXCAN_WriteTxMb(BSP_CAN_BASE, TX_MB_IDX, &sdk_frame);
if (wr_status != kStatus_Success) if (wr_status != kStatus_Success)
{ {
return BSP_ERR_BUSY; return BSP_ERR_BUSY;
} }
/* Ждать завершения передачи с таймаутом. */
uint64_t tx_flag = (uint64_t) 1U << TX_MB_IDX; uint64_t tx_flag = (uint64_t) 1U << TX_MB_IDX;
uint32_t start_ms = bsp_tick_get_ms(); uint32_t start_ms = bsp_tick_get_ms();
@ -442,7 +432,6 @@ bsp_status_t bsp_can_send(const bsp_can_frame_t *p_frame, uint32_t timeout_ms)
} }
} }
/* Очистить флаг завершения. */
FLEXCAN_ClearMbStatusFlags(BSP_CAN_BASE, tx_flag); FLEXCAN_ClearMbStatusFlags(BSP_CAN_BASE, tx_flag);
return BSP_OK; return BSP_OK;
@ -471,16 +460,13 @@ bsp_status_t bsp_can_receive(bsp_can_frame_t *p_frame, uint32_t timeout_ms)
for (;;) for (;;)
{ {
/* Опросить все активные MB, сложить в ring buffer. */
poll_rx_mailboxes(); poll_rx_mailboxes();
/* Попробовать извлечь фрейм. */
if (try_dequeue_frame(p_frame)) if (try_dequeue_frame(p_frame))
{ {
return BSP_OK; return BSP_OK;
} }
/* Проверить таймаут. */
uint32_t elapsed = bsp_tick_get_ms() - start_ms; uint32_t elapsed = bsp_tick_get_ms() - start_ms;
if (elapsed >= timeout_ms) if (elapsed >= timeout_ms)
{ {

View file

@ -110,11 +110,6 @@ static void mqs_edma_callback(I2S_Type *p_base, sai_edma_handle_t *p_handle, sta
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* Публичный API * Публичный API
* ----------------------------------------------------------------------- */ * ----------------------------------------------------------------------- */
/*
* AUDIO PLL setting: Frequency = Fref * (DIV_SELECT + NUM / DENOM)
* = 24 * (32 + 768/1000)
* = 786.432 MHz
*/
bsp_status_t bsp_mqs_init(void) bsp_status_t bsp_mqs_init(void)
{ {

View file

@ -12,7 +12,6 @@
* Пин LOW (тока нет) BSP_OPTO_STATE_INACTIVE * Пин LOW (тока нет) BSP_OPTO_STATE_INACTIVE
* *
* Режимы каналов (bsp_opto_ch_mode_t): * Режимы каналов (bsp_opto_ch_mode_t):
* ы
* BSP_OPTO_MODE_LEVEL IN1, IN2 * BSP_OPTO_MODE_LEVEL IN1, IN2
* Детектирование уровня с программным дебаунсом. * Детектирование уровня с программным дебаунсом.
* ISR переключает направление прерывания (RISINGFALLING) после каждого фронта, * ISR переключает направление прерывания (RISINGFALLING) после каждого фронта,

View file

@ -26,7 +26,7 @@
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Константы */ /* Константы */
/* -------------------------------------------------s------------------------- */ /* -------------------------------------------------------------------------- */
/** Передать в timeout_ms чтобы ждать данные бесконечно. */ /** Передать в timeout_ms чтобы ждать данные бесконечно. */
#define BSP_UART_HOST_WAIT_FOREVER (UINT32_MAX) #define BSP_UART_HOST_WAIT_FOREVER (UINT32_MAX)

View file

@ -84,17 +84,14 @@ bsp_status_t bsp_uart_host_init(uint32_t baud_rate)
return BSP_ERR_INIT; return BSP_ERR_INIT;
} }
/* Инициализация кольцевого буфера. */
if (!ring_buffer_init(&g_s_rx_ring, g_s_rx_buf, BSP_UART_HOST_RX_BUFFER_SIZE)) if (!ring_buffer_init(&g_s_rx_ring, g_s_rx_buf, BSP_UART_HOST_RX_BUFFER_SIZE))
{ {
/* Размер не степень двойки — ошибка конфигурации. */ /* Размер не степень двойки — ошибка конфигурации. */
return BSP_ERR_INIT; return BSP_ERR_INIT;
} }
/* Тактирование LPUART1. */
CLOCK_EnableClock(kCLOCK_Lpuart1); CLOCK_EnableClock(kCLOCK_Lpuart1);
/* Настройка периферии. */
lpuart_config_t config; lpuart_config_t config;
LPUART_GetDefaultConfig(&config); LPUART_GetDefaultConfig(&config);
config.baudRate_Bps = baud_rate; config.baudRate_Bps = baud_rate;
@ -191,7 +188,6 @@ size_t bsp_uart_host_read(uint8_t *p_buf, size_t len, uint32_t timeout_ms)
continue; continue;
} }
/* Буфер пуст — проверяем таймаут. */
if (timeout_ms == 0U) if (timeout_ms == 0U)
{ {
break; break;

View file

@ -566,8 +566,6 @@ bsp_status_t bsp_usb_cdc_init(void)
USB_DeviceIsrEnable(); USB_DeviceIsrEnable();
/* FIXME:Задержка для стабилизации DP pull-down. */
//SDK_DelayAtLeastUs(USB_ATTACH_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
bsp_delay(USB_ATTACH_DELAY_US / 1000); bsp_delay(USB_ATTACH_DELAY_US / 1000);
USB_DeviceRun(g_usbDeviceHandle); USB_DeviceRun(g_usbDeviceHandle);

View file

@ -191,7 +191,7 @@ static size_t parse_string_array(const char *p_array_start, char (*p_out_bufs)[T
{ {
return 0U; return 0U;
} }
p++; /* пропустить '[' */ p++;
size_t count = 0U; size_t count = 0U;
while (count < max_items) while (count < max_items)
@ -285,8 +285,6 @@ static void handle_cmd_run_selected(const char *p_line)
/** /**
* @brief Обработать сообщение {"type":"cmd",...}. * @brief Обработать сообщение {"type":"cmd",...}.
*
* Команды: ping pong, run_all test_runner, run test_runner.
*/ */
static void handle_cmd(const char *p_line) static void handle_cmd(const char *p_line)
{ {

View file

@ -115,7 +115,6 @@ void protocol_send_confirm_request(const confirm_params_t *p_params)
void protocol_send_test_list(const test_module_t *const *p_pp_registry, size_t count) void protocol_send_test_list(const test_module_t *const *p_pp_registry, size_t count)
{ {
/* Заголовок массива */
cli_send("{\"type\":\"test_list\",\"tests\":["); cli_send("{\"type\":\"test_list\",\"tests\":[");
for (size_t i = 0U; i < count; i++) for (size_t i = 0U; i < count; i++)

View file

@ -91,7 +91,7 @@ static volatile bool g_s_confirm_value;
static char g_s_pending_confirm_id[RUNNER_CONFIRM_ID_SIZE]; static char g_s_pending_confirm_id[RUNNER_CONFIRM_ID_SIZE];
static uint32_t g_s_confirm_deadline_ms; static uint32_t g_s_confirm_deadline_ms;
/* Счётчики итога (используются только в RUNNER_MODE_ALL) */ /* Счётчики итога (ALL и SELECTED; в SINGLE не используются) */
static uint8_t g_s_passed; static uint8_t g_s_passed;
static uint8_t g_s_failed; static uint8_t g_s_failed;
static uint8_t g_s_skipped; static uint8_t g_s_skipped;

View file

@ -163,7 +163,6 @@ def main() -> int:
) )
args = parser.parse_args() args = parser.parse_args()
# ── Проверить FCB ─────────────────────────────────────────────────────────
if not args.fcb.exists(): if not args.fcb.exists():
print(f" ❌ FCB not found: {args.fcb}", file=sys.stderr) print(f" ❌ FCB not found: {args.fcb}", file=sys.stderr)
print( print(
@ -174,7 +173,6 @@ def main() -> int:
) )
return 1 return 1
# ── Найти HAB-образ ───────────────────────────────────────────────────────
hab_name = HAB_NAMES[args.firmware] hab_name = HAB_NAMES[args.firmware]
hab_path = BUILD_DIR / args.build_type / hab_name hab_path = BUILD_DIR / args.build_type / hab_name
@ -195,7 +193,6 @@ def main() -> int:
print(f" Target : {args.target}") print(f" Target : {args.target}")
print(f" Frequency : {args.frequency} Hz\n") print(f" Frequency : {args.frequency} Hz\n")
# ── Собрать объединённый образ ────────────────────────────────────────────
image = build_full_image(args.fcb, hab_path) image = build_full_image(args.fcb, hab_path)
if args.dry_run: if args.dry_run:
@ -205,7 +202,6 @@ def main() -> int:
print(f"\n Dry run — image saved to {out}") print(f"\n Dry run — image saved to {out}")
return 0 return 0
# ── Записать во Flash через pyOCD ─────────────────────────────────────────
with tempfile.NamedTemporaryFile( with tempfile.NamedTemporaryFile(
suffix=f"_{args.firmware}_full.bin", delete=False suffix=f"_{args.firmware}_full.bin", delete=False
) as tmp: ) as tmp:

View file

@ -387,7 +387,6 @@ def main() -> None:
), ),
) )
# Группа: что прошивать (взаимоисключающие варианты)
target_group = parser.add_mutually_exclusive_group() target_group = parser.add_mutually_exclusive_group()
target_group.add_argument( target_group.add_argument(
"--firmware", "--firmware",
@ -420,9 +419,6 @@ def main() -> None:
args = parser.parse_args() args = parser.parse_args()
# Валидация: --firmware требует --build-type (уже есть default, но запомним)
# --bin-path: build-type игнорируется
# --erase-chip: несовместим с --ram-only
if args.erase_chip and args.ram_only: if args.erase_chip and args.ram_only:
parser.error("--erase-chip несовместим с --ram-only") parser.error("--erase-chip несовместим с --ram-only")

View file

@ -4,8 +4,7 @@ TUI-приложение для диагностики и прошивки пл
Написано на Python + [Textual](https://textual.textualize.io/). Работает на Linux, macOS, Windows. Написано на Python + [Textual](https://textual.textualize.io/). Работает на Linux, macOS, Windows.
> Внутреннее устройство, диаграммы архитектуры и заметки для разработчиков — > Внутреннее устройство, диаграммы архитектуры и заметки для разработчиков —
> в [DEV_ARCH.md](DEV_ARCH.md). Этот документ — только про то, как приложением > в [DEV_ARCH.md](DEV_ARCH.md).
> пользоваться.
--- ---

View file

@ -50,8 +50,6 @@ class ServiceApp(App):
self.push_screen(WaitingScreen()) self.push_screen(WaitingScreen())
# ── Переходы между экранами ─────────────────────────────────────────────── # ── Переходы между экранами ───────────────────────────────────────────────
@on(WaitingScreen.DeviceDetected)
@on(WaitingScreen.DeviceDetected) @on(WaitingScreen.DeviceDetected)
def _on_device_detected(self, event: WaitingScreen.DeviceDetected) -> None: def _on_device_detected(self, event: WaitingScreen.DeviceDetected) -> None:
if event.mode == AppMode.FLASHING: if event.mode == AppMode.FLASHING:
@ -97,7 +95,6 @@ class ServiceApp(App):
@on(DiagScreen.DiagDone) @on(DiagScreen.DiagDone)
def _on_diag_done(self, event: DiagScreen.DiagDone) -> None: def _on_diag_done(self, event: DiagScreen.DiagDone) -> None:
"""После диагностики — отключиться, вернуться в Waiting."""
self._disconnect() self._disconnect()
self.switch_screen(WaitingScreen(disconnect_reason=event.reason)) self.switch_screen(WaitingScreen(disconnect_reason=event.reason))

View file

@ -33,11 +33,9 @@ from .models import TestInfo
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Таймаут чтения одной строки (сек)
_READLINE_TIMEOUT_S = 0.1 _READLINE_TIMEOUT_S = 0.1
# Таймаут ping→pong при подключении (сек)
_PING_TIMEOUT_S = 5.0 _PING_TIMEOUT_S = 5.0
# Таймаут ожидания событий теста (сек) — длиннее самого долгого теста (SDRAM ~15 с) # Длиннее самого долгого теста (SDRAM ~15 с)
_TEST_EVENT_TIMEOUT_S = 120.0 _TEST_EVENT_TIMEOUT_S = 120.0

View file

@ -30,7 +30,6 @@ import serial.tools.list_ports
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# VID/PID M5StampPLC
_M5_VID = int(os.environ.get("SERVICE_M5_VID", "0x303A"), 16) _M5_VID = int(os.environ.get("SERVICE_M5_VID", "0x303A"), 16)
_M5_PID = int(os.environ.get("SERVICE_M5_PID", "0x4001"), 16) _M5_PID = int(os.environ.get("SERVICE_M5_PID", "0x4001"), 16)

View file

@ -51,12 +51,10 @@ from .models import ConfirmRequest, TestResult, TestStatus
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Задержки для HIL
_RELAY_ON_S = 0.15 _RELAY_ON_S = 0.15
_RELAY_OFF_S = 0.50 _RELAY_OFF_S = 0.50
# Карта confirm_id → реле M5 для opto-теста # confirm_id → (relay_num, target_state)
# Формат: confirm_id → (relay_num, target_state)
_OPTO_RELAY_MAP: dict[str, tuple[int, bool]] = { _OPTO_RELAY_MAP: dict[str, tuple[int, bool]] = {
"opto_in1_active": (3, True), "opto_in1_active": (3, True),
"opto_in1_inactive": (3, False), "opto_in1_inactive": (3, False),
@ -66,7 +64,6 @@ _OPTO_RELAY_MAP: dict[str, tuple[int, bool]] = {
"opto_rs_inactive": (2, False), "opto_rs_inactive": (2, False),
} }
# CAN параметры
_CAN_RX_ID = 0x100 _CAN_RX_ID = 0x100
_CAN_RX_DATA = [0xDE, 0xAD, 0xBE, 0xEF] _CAN_RX_DATA = [0xDE, 0xAD, 0xBE, 0xEF]
_CAN_TX_ID = 0x200 _CAN_TX_ID = 0x200
@ -80,13 +77,13 @@ _TIMEOUT_EVENT_TYPE = "_timeout"
class OrchestratorEventType(Enum): class OrchestratorEventType(Enum):
TEST_BEGIN = auto() # тест начался TEST_BEGIN = auto()
TEST_RESULT = auto() # тест завершился TEST_RESULT = auto()
TEST_PROGRESS = auto() # внутришаговый прогресс долгого теста (usd и т.п.) TEST_PROGRESS = auto() # внутришаговый прогресс долгого теста (usd и т.п.)
CONFIRM_NEEDED = auto() # нужен ответ оператора (standalone) CONFIRM_NEEDED = auto() # нужен ответ оператора (standalone)
CONFIRM_RESOLVED = auto() # HIL confirm выполнен автоматически CONFIRM_RESOLVED = auto() # HIL confirm выполнен автоматически
BUTTONS_PROMPT = auto() # показать инструкцию для buttons (без confirm) BUTTONS_PROMPT = auto() # показать инструкцию для buttons (без confirm)
SUMMARY = auto() # итог всей сессии SUMMARY = auto()
ERROR = auto() # ошибка протокола, M5, или обрыв по таймауту ERROR = auto() # ошибка протокола, M5, или обрыв по таймауту

View file

@ -24,7 +24,6 @@ class TestListPanel(Widget):
def __init__(self, **kwargs) -> None: def __init__(self, **kwargs) -> None:
super().__init__(**kwargs) super().__init__(**kwargs)
# test_id → Checkbox для быстрого доступа
self._checkboxes: dict[str, Checkbox] = {} self._checkboxes: dict[str, Checkbox] = {}
# test_id → True если HIL-тест недоступен без M5 (постоянное состояние, # test_id → True если HIL-тест недоступен без M5 (постоянное состояние,
# не зависящее от прогона). Отдельно от Checkbox.disabled, который # не зависящее от прогона). Отдельно от Checkbox.disabled, который

View file

@ -173,9 +173,8 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
self._stop_connection_watch() self._stop_connection_watch()
def _check_sdp_present(self) -> bool: def _check_sdp_present(self) -> bool:
# Не считаем потерей соединения, если идёт активная операция — # Не считаем потерей соединения, если идёт активная операция — обрыв
# flash_usb.py сам обработает реальный обрыв через subprocess. # в этом случае обнаружит и обработает сам flash_backend
# обрыв в этом случае обнаружит и обработает сам flash_backend
# (ConnectionLostError, см. Фазу 4), не watcher. # (ConnectionLostError, см. Фазу 4), не watcher.
if self._flashing: if self._flashing:
return True return True

View file

@ -329,7 +329,6 @@ def test_flash_write_memory_fails(monkeypatch, events, tmp_path):
with pytest.raises(fb.FlashBackendError, match="write_memory"): with pytest.raises(fb.FlashBackendError, match="write_memory"):
fb.flash(hab_bin, progress_cb=_collector(events)) fb.flash(hab_bin, progress_cb=_collector(events))
# reset/done не должны наступить после ошибки записи
assert "reset" not in _phases(events) assert "reset" not in _phases(events)
assert "done" not in _phases(events) assert "done" not in _phases(events)