Files
Balsam_167/tests/ump_can_init/model.inc
Andrey 04a9d989fb Исправить TESTLAMP, запуск CAN и расчёт фазных токов
Сохранить состояние TESTLAMP при кратких провалах входа и исключить повторный вход Timer1 во время передачи индикации.
Явно сбрасывать служебный обмен CAN при запуске и выбирать соседнюю фазу по локальному индексу канала АЦП.
Сохранить текущую последовательность DATA/CLK и проверочные варианты таймингов, добавить поведенческие тесты и обновить образ прошивки с картой памяти.
2026-10-13 14:13:43 +03:00

88 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdint.h> /* Задаёт точные размеры регистров и слов протокола при исполнении модели на ПК. */
#include "ump_tms28335.h" /* Подключает настоящий интерфейс проверки запросов и упаковки фрагментов CAN. */
#define UMP_CAN_MAX_WORDS UMP_MAX_WORDS /* Повторяет максимальную длину ответа из рабочего заголовка адаптера. */
#define UMP_CAN_MARKER UMP_MARKER /* Использует каноническую метку отличия служебного кадра от технологических данных. */
#define ump_can_prepare ump_tms28335_prepare /* Сохраняет штатное соответствие имени адаптера канонической функции порта. */
#define ANSWER_LEN 128U /* Моделирует границу штатных технологических регистров для компиляции настоящего Handlai. */
#define dsk_LOAD 6 /* Повторяет номер платы нагрузки из package.h для компиляции технологической ветви Handlai; сценарии используют служебные кадры. */
#define CHECK(condition) do { if (!(condition)) return __LINE__; } while (0) /* Сохраняет проверки при O3 и возвращает точное место регрессии вызывающему Python. */
struct MODEL_REG { uint32_t all; }; /* Моделирует атомарное 32-битное чтение и запись слова аппаратного регистра. */
struct MODEL_MAILBOX { struct MODEL_REG MDL, MDH; struct { struct { unsigned int DLC; } bit; } MSGCTRL; }; /* Предоставляет реальные имена полей данных и длины кадра, читаемые рабочим кодом. */
struct ECAN_MBOXES { struct MODEL_MAILBOX MBOX1, MBOX2; }; /* Отделяет входящий запрос в mailbox 1 от служебного ответа в mailbox 2. */
static struct { struct MODEL_REG CANTA, CANAA, CANTRR, CANTRS; } ECanaRegs; /* Хранит подтверждения, отмену и факт запуска передачи для наблюдения сценарием. */
static struct ECAN_MBOXES ECanaMboxes; /* Предоставляет обработчикам адресуемую память вместо физической периферии. */
static struct { unsigned long InterruptCount; } CpuTimer1; /* Задаёт миллисекундное время, от которого сервис считает тайм-аут ожидания ответа. */
static int modbus[ANSWER_LEN], Desk, Lonely; /* Обеспечивает зависимости технологической ветви Handlai, не исполняемой при служебном запросе. */
static unsigned int model_reads, model_writes, model_unexpected, model_irq_mask; /* Позволяет отличить ложную команду, корректное чтение и несбалансированную блокировку IRQ. */
static unsigned int __disable_interrupts(void) { unsigned int saved = model_irq_mask; model_irq_mask = 1; return saved; } /* Имитирует сохранение предыдущей маски, чтобы вложенные вызовы оставались проверяемыми. */
static void __restore_interrupts(unsigned int saved) { model_irq_mask = saved; } /* Возвращает исходную маску и позволяет сценарию обнаружить оставленную блокировку. */
static void Load_voltage_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c) { (void)header; (void)a; (void)b; (void)c; model_unexpected++; } /* Считает ошибочным попадание служебного запроса в обработку технологического напряжения. */
static void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c) { (void)header; (void)a; (void)b; (void)c; model_unexpected++; } /* Обнаруживает лишнюю регистрацию служебного опроса как управляющего CAN-события. */
static void led2_toggle(void) { model_unexpected++; } /* Отмечает проход по обычной ветви CAN вместо раннего возврата служебного запроса. */
static unsigned int Load_protection_prepare(unsigned int fn, uint16_t address, uint16_t value, uint16_t *reply, unsigned int *error) { (void)fn; (void)address; (void)value; (void)reply; *error = 2; model_unexpected++; return 0; } /* Запросы теста адресуют журнал, поэтому попадание в карту защиты является ошибкой маршрутизации. */
#if EEPROM_M95M02 /* Компилирует зависимости дополнительной ветви так же, как прошивка профиля M95M02. */
static int gas167_contains(uint16_t address) { return address >= 0x5000U && address < 0x5080U; } /* Отделяет область GAS от проверяемого журнала, не копируя реализацию профиля. */
static unsigned int gas167_prepare(unsigned int fn, uint16_t address, uint16_t value, int can, uint16_t *reply, unsigned int *error) { (void)fn; (void)address; (void)value; (void)can; (void)reply; *error = 2; model_unexpected++; return 0; } /* Делает неожиданное обращение к GAS наблюдаемой ошибкой в тесте запуска журнала. */
#endif /* Завершает минимальные зависимости профиля, не подменяя проверку общей CAN-маршрутизации. */
unsigned int ump_log_read(unsigned int address) { model_reads++; return 0x5500U + address - UMP_BASE; } /* Возвращает узнаваемые слова backend, чтобы ответ нельзя было спутать со старым содержимым RAM. */
int ump_log_write(unsigned int address, unsigned int value) { (void)address; (void)value; model_writes++; return 1; } /* Регистрирует любую нежелательную запись, случайно возникшую из остаточного запроса. */
/* PRODUCTION_CAN */
static void model_reset_hardware(void) /* Очищает только модель периферии; управляющую RAM оставляет сценарию для воспроизведения холодного старта. */
{ /* Начинает воспроизводимое состояние аппаратных mailbox после сброса контроллера. */
ECanaRegs.CANTA.all = 0; ECanaRegs.CANAA.all = 0; ECanaRegs.CANTRR.all = 0; ECanaRegs.CANTRS.all = 0; /* Убирает подтверждения и запросы, которые аппаратный сброс не сохраняет вместе с RAM. */
ECanaMboxes.MBOX2.MDL.all = 0; ECanaMboxes.MBOX2.MDH.all = 0; /* Обнуляет наблюдаемые данные ответа для обнаружения каждой новой передачи. */
CpuTimer1.InterruptCount = 1000; model_reads = 0; model_writes = 0; model_unexpected = 0; model_irq_mask = 0; /* Задаёт миллисекундный такт и независимые счётчики нового сценария. */
} /* Завершает аппаратный сброс без скрытой инициализации проверяемых переменных прошивки. */
static void model_poison_state(void) /* Воссоздаёт допустимые остатки RAM, ранее приводившие к ответу без входного запроса. */
{ /* Начинает заполнение всех управляющих полей ненулевыми либо специально подобранными значениями. */
ump_can_pending = 0; ump_can_tag = 0xA506U; ump_can_address = UMP_BASE; ump_can_value = 1; /* Сохраняет след прежней команды записи, но отмечает отсутствие нового принятого запроса. */
ump_can_length = 2; ump_can_index = 0; ump_can_reply_tag = 0x0100U; ump_can_waiting = 0; ump_can_sent_at = 777; /* Представляет старый двухсловный ответ с token 1, который сервис ошибочно считает готовым. */
ump_can_reply[0] = 0x1234U; ump_can_reply[1] = 0x5678U; /* Создаёт отличимый от backend payload для доказательства отправки именно остаточного буфера. */
} /* Завершает заполнение состояния, которое настоящий сброс обязан обезвредить. */
static int model_first_request(unsigned int token) /* Проверяет весь первый ответ после сброса через настоящий приёмник, валидатор и упаковщик. */
{ /* Начинает независимую транзакцию чтения 16 слов заголовка журнала. */
unsigned int fragment; /* Перебирает восемь CAN-фрагментов, каждый из которых содержит два 16-битных слова. */
ECanaMboxes.MBOX1.MDH.all = ((uint32_t)UMP_CAN_MARKER << 16) | ((uint32_t)token << 8) | 3U; /* Формирует служебную метку, новый token и штатную функцию чтения FC03. */
ECanaMboxes.MBOX1.MDL.all = ((uint32_t)UMP_BASE << 16) | 16U; ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8; /* Запрашивает допустимый восьмибайтный кадр чтения полного 16-словного заголовка. */
Handlai(&ECanaMboxes); /* Передаёт запрос настоящему разборщику mailbox без прямой установки поля pending. */
CHECK(ump_can_pending == 1 && model_reads == 0 && model_writes == 0); /* Проверяет, что ISR только опубликовал запрос и не исполнил его вместо главного цикла. */
for (fragment = 0; fragment < 8; fragment++) { /* Проверяет все фрагменты, включая последний, чтобы сброс счётчиков не скрывал укороченный ответ. */
UMP_CAN_service(); /* Готовит снимок при первом вызове и далее отправляет по одному настоящему фрагменту. */
CHECK(ECanaRegs.CANTRS.all == 4 && ump_can_waiting == 1); /* Требует запуска mailbox 2 и ожидания подтверждения именно отправленного кадра. */
CHECK(ECanaMboxes.MBOX2.MDL.all == (((uint32_t)(0x5500U + fragment * 2U) << 16) | (0x5501U + fragment * 2U))); /* Сравнивает оба слова кадра с содержимым нового снимка, исключая остатки прежнего ответа. */
CHECK(ECanaMboxes.MBOX2.MDH.all == (((uint32_t)(UMP_CAN_MARKER + fragment) << 16) | ((uint32_t)token << 8))); /* Проверяет порядок фрагментов, token текущего запроса и отсутствие кода ошибки. */
ECanaRegs.CANTRS.all = 0; ECanaRegs.CANTA.all = 4; /* Имитирует окончание передачи и подтверждение только проверенного фрагмента аппаратурой CAN. */
} /* Завершает передачу всех 16 запрошенных слов. */
UMP_CAN_service(); ECanaRegs.CANTA.all = 0; /* Позволяет сервису принять последнее подтверждение; затем моделирует очистку W1C-регистра аппаратурой. */
CHECK(ECanaRegs.CANTRS.all == 0 && ump_can_waiting == 0 && ump_can_pending == 0); /* Убеждается, что после последнего ACK не отправляется лишний либо старый фрагмент. */
CHECK(model_reads == 16 && model_writes == 0 && model_unexpected == 0 && model_irq_mask == 0); /* Требует единственного согласованного снимка, отсутствия ложных команд и восстановленной маски IRQ. */
return 0; /* Сообщает вызывающему сценарию о полном успешном ответе после инициализации. */
} /* Завершает поведенческую проверку первой транзакции. */
#ifdef _WIN32 /* Экспортирует тест явно для загрузки MinGW DLL через ctypes в Windows. */
__declspec(dllexport) /* Делает run_tests видимой снаружи библиотеки без таблицы экспорта проекта прошивки. */
#endif /* На остальных платформах используется обычная видимость глобальной функции. */
int run_tests(void) /* Возвращает ноль только при выполнении всех сценариев запуска и повторного сброса. */
{ /* Начинает проверку реального дефекта до сброса и его устранения рабочим helper. */
int result; /* Передаёт точную строку сбоя из сценария полной CAN-транзакции. */
model_reset_hardware(); model_poison_state(); UMP_CAN_service(); /* Воспроизводит старое поведение на грязной RAM без вызова добавленного сброса. */
CHECK(ECanaRegs.CANTRS.all == 4 && ECanaMboxes.MBOX2.MDL.all == 0x12345678UL && ump_can_pending == 0); /* Доказывает самопроизвольный ответ, чтобы тест не оказался нечувствителен к исходной регрессии. */
model_reset_hardware(); model_poison_state(); ump_can_init(); /* Вызывает настоящий новый сброс при тех же остатках RAM и чистой периферии. */
CHECK(ump_can_pending == 0 && ump_can_tag == 0 && ump_can_address == 0 && ump_can_value == 0); /* Проверяет, что старые параметры не смогут превратиться в ложную принятую команду. */
CHECK(ump_can_length == 0 && ump_can_index == 0 && ump_can_reply_tag == 0 && ump_can_waiting == 0 && ump_can_sent_at == 0); /* Требует очистки всех управляющих полей незавершённой передачи и тайм-аута. */
UMP_CAN_service(); UMP_CAN_service(); /* Даёт главному циклу повторно обработать состояние до появления первого запроса. */
CHECK(ECanaRegs.CANTRS.all == 0 && ECanaRegs.CANTRR.all == 0 && model_reads == 0 && model_writes == 0); /* Запрещает ложную передачу, отмену несуществующего кадра и исполнение остаточной команды. */
result = model_first_request(0x37U); if (result) return result; /* Проверяет приём и все фрагменты первого запроса после холодного запуска. */
model_reset_hardware(); model_poison_state(); ump_can_waiting = 1; ump_can_pending = 1; /* Воспроизводит перезапуск во время передачи с ещё не обработанным старым запросом в RAM. */
ump_can_init(); CpuTimer1.InterruptCount += 1000; UMP_CAN_service(); /* Проверяет сброс ожидания даже после истечения прежнего тайм-аута в 250 мс. */
CHECK(ECanaRegs.CANTRS.all == 0 && ECanaRegs.CANTRR.all == 0 && ump_can_pending == 0 && ump_can_waiting == 0); /* Не допускает зависания в отмене старого mailbox либо исполнения устаревшего pending. */
result = model_first_request(0x59U); if (result) return result; /* Доказывает, что после такого перезапуска новый token обслуживается полной последовательностью фрагментов. */
return 0; /* Подтверждает исправление холодного старта без изменения алгоритма штатного CAN-ответа. */
} /* Завершает экспортированную проверку регрессии для выбранного профиля EEPROM. */