#include "boot_control_hal.h" /* Подключает совместимый API приложения climate. */ #include "boot_profile.h" /* Получает общий адрес SRAM-запроса и карту Flash. */ #include "pcan_boot_config.h" /* Идентичность прибора остаётся настройкой проекта, общей для boot и app. */ HAL_StatusTypeDef CanBootControl_Start(CAN_HandleTypeDef *can) /* Сохраняет прежнюю настройку выделенного CAN приложения. */ { /* Новые приложения с DeviceCan используют только Handle и собственные адресные фильтры. */ CAN_FilterTypeDef filter = {0}; /* Исключает неопределённые поля аппаратной конфигурации. */ if (can == NULL) return HAL_ERROR; /* Не обращается к отсутствующему HAL handle. */ filter.FilterBank = 0U; filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterScale = CAN_FILTERSCALE_32BIT; /* Сохраняет широкую фильтрацию старого выделенного канала; адрес проверяется программно. */ filter.FilterFIFOAssignment = CAN_RX_FIFO0; filter.FilterActivation = ENABLE; filter.SlaveStartFilterBank = 14U; /* Использует FIFO0 и штатное разделение банков CAN1/CAN2. */ if (HAL_CAN_ConfigFilter(can, &filter) != HAL_OK) return HAL_ERROR; /* Не запускает CAN с неподтверждённым фильтром. */ return HAL_CAN_Start(can); /* Возвращает вызывающему приложению фактический результат запуска. */ } /* Завершает совместимую настройку транспорта приложения. */ void CanBootControl_Poll(CAN_HandleTypeDef *can) /* Поддерживает старые приложения без отдельного распределителя входящих кадров. */ { /* Приём ограничен одним кадром, чтобы не блокировать главный цикл. */ CAN_RxHeaderTypeDef header; uint8_t data[8]; /* Выделяет полный буфер classic CAN независимо от входящего DLC. */ if (can != NULL && HAL_CAN_GetRxFifoFillLevel(can, CAN_RX_FIFO0) != 0U && HAL_CAN_GetRxMessage(can, CAN_RX_FIFO0, &header, data) == HAL_OK) (void)CanBootControl_Handle(&header, data); /* Передаёт только успешно принятый кадр общему обработчику. */ } /* Завершает опрос канала совместимости. */ uint8_t CanBootControl_Handle(const CAN_RxHeaderTypeDef *header, const uint8_t data[8]) /* Запускает обновление только для собственного адреса и ненулевой сессии. */ { /* Ответ ENTER_BOOT отправляет уже загрузчик после повторного запроса клиента. */ uint32_t id; /* Сохраняет проверенный расширенный CAN ID запроса. */ (void)data; /* ENTER_BOOT не содержит payload и не должен читать входной буфер. */ if (header == NULL || header->IDE != CAN_ID_EXT || header->RTR != CAN_RTR_DATA || header->DLC != 0U || header->ExtId > 0x1FFFFFFFUL) return 0U; /* Отвергает стандартные, remote и ошибочно дополненные запросы. */ id = header->ExtId; /* Извлекает идентификатор только после проверки внешнего заголовка. */ if (((id >> 27U) & 1U) != 0U || ((id >> 24U) & 7U) != PCAN_BOOT_DEVICE_TYPE || ((id >> 20U) & 15U) != PCAN_BOOT_DEVICE_ID || ((id >> 16U) & 15U) != 9U || (id & 255U) != 2U || ((id >> 8U) & 255U) == 0U) return 0U; /* Сопоставляет Route=0, адрес, BOOT_CONTROL=9, ENTER_BOOT=2 и SessionID != 0. */ *((volatile uint32_t *)(uintptr_t)PCAN_BOOT_REQUEST_ADDRESS) = PCAN_BOOT_REQUEST_MAGIC; /* Сохраняет одноразовый запрос в слове SRAM, исключённом из linker-стека. */ __DSB(); /* Дожидается записи SRAM перед системным reset. */ NVIC_SystemReset(); /* Передаёт управление общему загрузчику без подтверждения из приложения. */ return 1U; /* Позволяет тестовой модели и старому диспетчеру отметить обработанный запрос. */ } /* Завершает безопасную проверку входа в загрузчик. */