diff --git a/Inc/DS_Accord_8_F-CAN.h b/Inc/DS_Accord_8_F-CAN.h new file mode 100644 index 0000000..7ab88eb --- /dev/null +++ b/Inc/DS_Accord_8_F-CAN.h @@ -0,0 +1,23 @@ +#ifndef __DS_Accord_8_F-CAN_H +#define __DS_Accord_8_F-CAN_H + +#include "main.h" + +// Структура описания CAN-пакета для диспетчера задач (Scheduler) +typedef struct { + uint16_t id; // CAN ID пакета + uint8_t dlc; // Длина кадра (DLC) + uint32_t period; // Период отправки в миллисекундах (мс) + uint32_t last_time; // Таймер последнего запуска (GetTick) + uint8_t alive_cnt; // Текущий шаг Alive Counter (0..3) + uint32_t start_phase; // Сдвиг запуска в миллисекундах + uint8_t data[8]; // ПОЛЕЗНАЯ НАГРУЗКА: +} CanTaskTypeDef; + +/* Прототипы функций для вызова в основном проекте */ +void run_honda_simulation(void); +uint8_t calc_honda_halfbyte_checksum(uint16_t id, uint8_t *data, uint8_t dlc, uint8_t alive_val); + +extern volatile CanTaskTypeDef tasks[]; + +#endif /* __DS_Accord_8_F-CAN_H */ diff --git a/Src/DS_Accord_8_F-CAN.c b/Src/DS_Accord_8_F-CAN.c new file mode 100644 index 0000000..9263613 --- /dev/null +++ b/Src/DS_Accord_8_F-CAN.c @@ -0,0 +1,126 @@ +#include "DS_Accord_8_F-CAN.h" + +// Внешний дескриптор CAN из main.c +extern CAN_HandleTypeDef hcan; + +// Массив пакетов симуляции +volatile CanTaskTypeDef tasks[] = { + // ID, DLC, Period, Alive, Last_Time, Start_Phase, { Исходные данные DATA[8] } + {0x158, 8, 10, 0, 0, 0, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}}, // ECU Скорость + {0x17C, 8, 10, 0, 0, 2, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // + {0x1A4, 8, 20, 0, 0, 4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // ABS/VSA Тормоза + {0x324, 8, 20, 0, 0, 6, {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // MICU Кузов + + // {0x490, 8, 20, 0, 0, 6, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x491, 8, 20, 0, 0, 6, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x492, 8, 20, 0, 0, 8, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x493, 8, 20, 0, 0, 8, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x494, 8, 20, 0, 0, 9, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x495, 8, 20, 0, 0, 9, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x496, 8, 20, 0, 0, 1, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x497, 8, 20, 0, 0, 9, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x498, 8, 20, 0, 0, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x499, 8, 20, 0, 0, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x49A, 8, 20, 0, 0, 5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x49B, 8, 20, 0, 0, 5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x49C, 8, 20, 0, 0, 7, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x49D, 8, 20, 0, 0, 7, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x49E, 8, 20, 0, 0, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}}, + // {0x49F, 8, 20, 0, 0, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}} + +}; + +static const uint8_t num_tasks = sizeof(tasks) / sizeof(tasks[0]); +static const uint8_t alive_seq[] = {0, 1, 2, 3}; + +/** + * @brief Главный диспетчер циклической симуляции пакетов для Honda Accord 8 + * @note Должен вызываться в основном бесконечном цикле while(1) в main.c + */ +void run_honda_simulation(void) +{ + uint32_t current_tick = HAL_GetTick(); + CAN_TxHeaderTypeDef tx_header; + uint8_t tx_data[8]; // Временный буфер для формирования финального кадра + uint32_t tx_mailbox; + + for (uint8_t i = 0; i < num_tasks; i++) + { + // Настройка стартовой фазы при первом запуске + if (tasks[i].last_time == 0) + { + tasks[i].last_time = current_tick + tasks[i].start_phase; + } + + // Проверка временной сетки + if (current_tick < tasks[i].last_time) + { + continue; + } + + // Проверка свободного места в Mailbox пула + if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0) + { + continue; + } + + // Сдвигаем временную метку на период вперед + tasks[i].last_time += tasks[i].period; + + // Копируем текущие данные из структуры во временный буфер отправки + for (uint8_t b = 0; b < 8; b++) + { + tx_data[b] = tasks[i].data[b]; + } + + // Конфигурируем заголовок CAN + tx_header.StdId = tasks[i].id; + tx_header.DLC = tasks[i].dlc; + tx_header.RTR = CAN_RTR_DATA; + tx_header.IDE = CAN_ID_STD; + tx_header.TransmitGlobalTime = DISABLE; + + // Расчитываем динамическую контрольную сумму Honda на основе текущих данных + uint8_t current_alive = alive_seq[tasks[i].alive_cnt]; + uint8_t checksum_nibble = calc_honda_halfbyte_checksum(tx_header.StdId, tx_data, tx_header.DLC, current_alive); + + // Внедряем Alive счетчик и чексумму в самый последний байт пакета + tx_data[tx_header.DLC - 1] = (uint8_t)((current_alive << 4) | checksum_nibble); + + // Отправляем пакет в пул Mailbox + if (HAL_CAN_AddTxMessage(&hcan, &tx_header, tx_data, &tx_mailbox) == HAL_OK) + { + tasks[i].alive_cnt = (tasks[i].alive_cnt + 1) % 4; + } + } +} + + + +/** + * @brief Математически выверенный алгоритм подсчета Check Byte для Accord 8 (Сумма полубайт + DLC) + */ +uint8_t calc_honda_halfbyte_checksum(uint16_t id, uint8_t *data, uint8_t dlc, uint8_t alive_val) +{ + uint32_t sum = 0; + + // 1. Складываем полубайты 11-битного CAN ID + sum += (id >> 8) & 0x0F; + sum += (id >> 4) & 0x0F; + sum += id & 0x0F; + + // 2. Складываем полубайты тела пакета (все, кроме последнего контрольного байта) + for (int i = 0; i < (dlc - 1); i++) + { + sum += (data[i] >> 4) & 0x0F; + sum += data[i] & 0x0F; + } + + // 3. Добавляем длину пакета и шаг циклического счетчика + sum += dlc & 0x0F; + sum += alive_val & 0x0F; + + // 4. Реализация правила дополнения до нуля (вычитание накопленного остатка из 16) + return (uint8_t)((0x10 - (sum & 0x0F)) & 0x0F); +} +