Files
Balsam_167/tests/load_control/load_control_test.c
Andrey 1e911e5250 Обновить логгер УМП и исправить запуск UART и EEPROM
Перейти на компактные 12-словные записи v4 и сохранять 10 процентов банка после отключения. Добавить трёхсекундное ожидание роста ЗПТ и настраиваемый лимит пусков. Явно инициализировать состояние UART и гарантировать публикацию параметров EEPROM перед запуском Timer2. Сохранить воспроизводимые сборки, регрессионные проверки, документацию и обновлённые результаты сборки; исключить временные артефакты.
2026-10-12 12:25:41 +03:00

354 lines
39 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.
/* Проверка load_control на модели ПК. Русские пояснения сохранены в UTF-8. */
/* Подключает <stdio.h>: настройки и интерфейс stdio. */
#include <stdio.h>
/* Подключает <string.h>: настройки и интерфейс string. */
#include <string.h>
/* Подключает "../../Source/Internal/DAC.c": выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
#include "../../Source/Internal/DAC.c"
/* Объявляет READY — данные READY; Desk — аппаратно определённый тип платы; Mode — рабочий адрес или режим платы, выбранный перемычками. Начальное значение задаётся справа от знака равенства. */
int READY = 1, Desk = 6, Mode = 5;
/* Объявляет modbus — массив технологических регистров; слово int на C28x занимает 16 бит. */
int modbus[128];
/* Объявляет test_start — данные test_start; test_stop — данные test_stop; test_permission — данные test_permission; test_tick — данные test_tick. */
unsigned int test_start, test_stop, test_permission, test_tick;
/* Объявляет test_starts — данные test_starts; test_last_stop_tick — данные test_last_stop_tick; test_last_start_tick — данные test_last_start_tick; test_init_dac — test init ЦАП. */
unsigned int test_starts, test_last_stop_tick, test_last_start_tick, test_init_dac;
/* Объявляет test_bad_order — данные test_bad_order. */
int test_bad_order;
/* Задаёт CHECK = do { if (!(x)) { printf("FAIL line %d: %s\n", __LINE__, #x); return 1; } } while (0); данные CHECK. */
#define CHECK(x) do { if (!(x)) { printf("FAIL line %d: %s\n", __LINE__, #x); return 1; } } while (0)
/* Начинает функцию setup; назначение модуля — проверка load_control на модели ПК. */
static void setup(int mode) {
/* Записывает Mode значением mode; READY = 1; рабочий адрес или режим платы, выбранный перемычками. */
memset(modbus, 0, sizeof(modbus)); Mode = mode; READY = 1;
/* Записывает test_start значением test_stop = test_permission = test_tick = test_starts = 0; данные test_start. */
test_start = test_stop = test_permission = test_tick = test_starts = 0;
/* Записывает test_bad_order значением test_init_dac = 0; данные test_bad_order. */
test_bad_order = test_init_dac = 0;
/* Записывает WAKEpowse значением 0; данные WAKEpowse. */
Load_control_init(); Setup_DAC_time(); WAKEpowse = 0;
/* Записывает DAC_go значением 4; DAC_stop = 16; DAC_min() = 100; DAC_max() = 3000; начальный ток нагрузки в мА, технологический регистр 0x50. */
DAC_go = 4; DAC_stop = 16; DAC_min() = 100; DAC_max() = 3000;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию tick; назначение модуля — проверка load_control на модели ПК. */
static void tick(unsigned int n, int exchange, unsigned int volts) {
/* Повторяет или ожидает, пока выполняется while (n--). */
while (n--) {
/* Проверяет if (exchange) Load_voltage_can(0x8000U | (Mode == 5 ? 305U : 8U), volts, 0, 0); последующий оператор выполняется только при истинном условии. */
if (exchange) Load_voltage_can(0x8000U | (Mode == 5 ? 305U : 8U), volts, 0, 0);
/* Изменяет счётчик в выражении test_tick++; Load_runner(); на один для следующего шага. */
test_tick++; Load_runner();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет штатные 6 мА, трёхсекундную реакцию ЗПТ и сохранение защитных остановов на настоящем DAC.c. */
static int startup_test(void) {
/* mode перебирает УМП 5/6, attempt контролирует пять пусков, code хранит отправленный код, count — оставшиеся токовые такты ожидания. */
unsigned int mode, attempt, code, count;
/* Проверяет оба штатных CAN-индекса: ЗПТ1 у УМП 5 и ЗПТ2 у УМП 6. */
for (mode = 5; mode <= 6; mode++) {
/* Подаёт START при заводских 6 мА и свежем нулевом ЗПТ; первые 10 мс включают базовый и стартовый кадры ЦАП. */
setup(mode); DAC_go = 6; Commands = 0x80; tick(10, 1, 0);
/* Первая попытка должна удерживать разрешение и получить 6 мА вместо мгновенного STOP. */
CHECK(test_starts == 1 && test_start && test_permission && !test_stop && modbus[0x1C] == 60 && modbus[123] != DAC_min());
/* Запоминает код 6 мА для исключения скрытого повышения тока до подтверждённых 30 В. */
code = modbus[123];
/* Проверяет последний миллисекундный такт перед тремя секундами от первой отправки 6 мА. */
tick(2999, 1, 29);
/* До конца выдержки сохраняет одну попытку, рабочее состояние и прежнее задание в масштабе 0,1 мА. */
CHECK(load_state == LOAD_RUN && load_attempts == 1 && modbus[0x1C] == 60 && (unsigned int)modbus[123] == code);
/* Ровно через 3000 мс свежее ЗПТ ниже 30 В должно завершить попытку защитным сбросом. */
tick(1, 1, 29);
/* Проверяет STOP, снятое разрешение и передачу базового тока 4 мА через калибровочный минимум. */
CHECK(load_state == LOAD_RELOAD && test_stop && !test_permission && modbus[0x1C] == 40 && modbus[123] == DAC_min());
/* После секунды STOP вторая попытка должна снова получить 6 мА и собственные три секунды ожидания. */
tick(1000, 1, 0);
/* Исключает повторный START и немедленный STOP в одном вызове обработчика. */
CHECK(test_starts == 2 && test_start && !test_stop && modbus[0x1C] == 60);
/* Проходит оставшиеся четыре попытки по реальному миллисекундному времени без ускорения рампы. */
for (attempt = 2; attempt <= 5; attempt++) {
/* Даёт каждой попытке 3000 мс свежего нулевого ЗПТ после начальной отправки 6 мА. */
tick(3000, 1, 0);
/* Проверяет возврат к 4 мА и полную выдержку каждой попытки до STOP. */
CHECK(test_stop && !test_permission && load_attempts == attempt && modbus[0x1C] == 40 && test_last_stop_tick - test_last_start_tick >= 3000);
/* До пятой попытки соблюдает дополнительную секунду STOP, после пятой повтор запрещён. */
if (attempt < 5) tick(1000, 1, 0);
/* Закрывает перебор разрешённых пусков. */
}
/* Достаточное ЗПТ после ошибки само по себе не должно давать шестой пуск. */
tick(3000, 1, 30);
/* Проверяет удержание ошибки, STOP и соблюдение порядка START/STOP/разрешения. */
CHECK(test_starts == 5 && (LOAD_STATUS & 1) && test_stop && !test_bad_order);
/* Закрывает независимые проверки обоих адресов УМП. */
}
/* Подаёт достаточное ЗПТ в последний такт выдержки: порог 30 В должен иметь приоритет перед истечением ожидания. */
setup(5); DAC_go = 6; Commands = 0x80; tick(3009, 1, 29); tick(1, 1, 30);
/* Проверяет, что на границе 3000 мс от первого токового кадра не произошло ложного STOP или второго START. */
CHECK(load_state == LOAD_RUN && test_starts == 1 && !test_stop && test_permission);
/* Даёт УМП 5 две секунды низкого ЗПТ при начальном токе 6 мА: первый токовый кадр отправляется на 10 мс. */
setup(5); DAC_go = 6; Commands = 0x80; tick(2010, 1, 29);
/* Устройство должно продолжать ожидание на первой попытке без роста выше 6 мА. */
CHECK(load_attempts == 1 && modbus[0x1C] == 60 && !test_stop);
/* Запоминает начальный код для проверки роста после прихода достаточного ЗПТ. */
code = modbus[123];
/* Ровно 30 В разрешают разгон; за 300 мс изменение видно даже при разрешении регистра 0,1 мА. */
tick(300, 1, 30);
/* Проверяет продолжение первой попытки и рост отправленного токового задания. */
CHECK(test_starts == 1 && load_state == LOAD_RUN && modbus[0x1C] > 60 && (unsigned int)modbus[123] > code);
/* После успешного роста падение до 29 В не получает дополнительную трёхсекундную выдержку. */
tick(5, 1, 29); CHECK(load_state == LOAD_RELOAD && test_stop && modbus[0x1C] == 40);
/* Даже повышенная начальная уставка 9 мА должна ограничиваться 6 мА до подтверждения роста ЗПТ. */
setup(5); DAC_go = 9; Commands = 0x80; tick(10, 1, 0);
/* Исключает преждевременную передачу повышенного начального задания при низком ЗПТ. */
CHECK(modbus[0x1C] == 60 && load_state == LOAD_RUN && test_starts == 1);
/* После исчезновения CAN отправленное задание должно остаться 6 мА, даже если начальная уставка равна 9 мА. */
tick(1000, 0, 0); CHECK((LOAD_STATUS & 2) && modbus[0x1C] == 60);
/* Короткий тайм-аут 20 мс позволяет проверить приостановку стартовой выдержки при потере выбранного CAN-напряжения. */
setup(5); DAC_go = 6; LOAD_CAN_TIMEOUT = 20; Commands = 0x80; tick(10, 1, 0);
/* Дожидается устаревания последнего ЗПТ без новых кадров. */
tick(30, 0, 0);
/* Сохраняет остаток стартовых отправок и последний код после перехода в паузу CAN. */
count = load_start_remaining; code = modbus[123];
/* Отсутствие CAN дольше всей выдержки не должно расходовать её остаток или следующую попытку. */
tick(4000, 0, 0);
/* Проверяет удержание кода, счётчика ожидания, разрешения и первой попытки во время тайм-аута. */
CHECK((LOAD_STATUS & 2) && load_start_remaining == count && (unsigned int)modbus[123] == code && load_attempts == 1 && !test_stop);
/* Свежее низкое ЗПТ возобновляет отсчёт от сохранённого значения. */
tick(5, 1, 29); CHECK(!(LOAD_STATUS & 2) && load_start_remaining == count - 1 && test_starts == 1);
/* RESET должен прекратить ожидание сразу и отправить 4 мА на ближайшем токовом такте. */
Commands = 0xC0; tick(5, 1, 29); CHECK(test_stop && !test_permission && modbus[0x1C] == 40);
/* Ручная калибровка вместе со START не должна подменять стартовое задание. */
setup(5); DAC_go = 6; Commands = 0x280; DAC_cal() = 4095; tick(6, 1, 0);
/* Команда инициализации на первом токовом такте не подтверждает отправку 6 мА и не расходует выдержку. */
cInitDac = 1; tick(4, 1, 0); CHECK(load_start_remaining == 600 && modbus[0x1C] == 40);
/* Следующий такт должен выдать настоящий начальный ток вместо ручного кода 4095. */
tick(5, 1, 0); CHECK(modbus[0x1C] == 60 && modbus[123] != 4095 && load_start_remaining == 599);
/* Последний такт перед тремя секундами от токового кадра ещё сохраняет ожидание. */
tick(2999, 1, 0); CHECK(load_state == LOAD_RUN);
/* Следующий такт завершает выдержку и возвращает 4 мА без подмены ручной калибровкой. */
tick(1, 1, 0); CHECK(load_state == LOAD_RELOAD && modbus[0x1C] == 40 && modbus[123] == DAC_min());
/* Возвращает успех после проверки реакции ЗПТ, пяти попыток, CAN, RESET и калибровки. */
return 0;
/* Закрывает проверку стартового этапа нагрузки. */
}
/* Проверяет настраиваемый лимит, независимость счётчика, уменьшение лимита в паузе STOP и верхнюю 16-битную границу. */
static int attempt_limit_test(void) {
/* Адреса 5/6 выбирают оба УМП; limit задаёт общий предел START, attempt считает проверяемые неудачи. */
unsigned int mode, limit, attempt, out[8], error;
/* Ноль из старой EEPROM должен превратиться в прежние заводские пять пусков. */
setup(5); CHECK(LOAD_MAX_ATTEMPTS == 5);
/* Подготовка тактов ЦАП после загрузки параметров обязана сохранять ненулевую пользовательскую настройку. */
LOAD_MAX_ATTEMPTS = 7; Setup_DAC_time(); CHECK(LOAD_MAX_ATTEMPTS == 7);
/* Проверяет одинаковый смысл лимита для ЗПТ1 и ЗПТ2, выбранных штатными CAN-адресами. */
for (mode = 5; mode <= 6; mode++) {
/* Значения 1, 2 и 7 проверяют отсутствие дополнительных пусков и снятие прежнего жёсткого предела пяти. */
for (limit = 1; limit <= 7; limit = limit == 1 ? 2 : 7) {
/* Новый сеанс начинает работу с указанным пределом; START включается только штатной командой. */
setup(mode); LOAD_MAX_ATTEMPTS = limit; Commands = 0x80;
/* Каждая успешная реакция ЗПТ позволяет затем проверить немедленную защиту при его падении. */
for (attempt = 1; attempt <= limit; attempt++) {
/* Даёт 1010 мс на первый пуск либо окончание секундного STOP перед очередным START. */
tick(1010, 1, 30);
/* Переводит рампу выше границы 6 мА при достаточном ЗПТ, затем имитирует его падение до нуля. */
load_count_ramp = time_dac / 6; tick(5, 1, 30); tick(5, 1, 0);
/* Проверяет число реальных START и неизменность записанного лимита после работы Timer1. */
CHECK(test_starts == attempt && load_attempts == attempt && LOAD_MAX_ATTEMPTS == (int)limit);
/* До последней попытки допускается повтор; последняя неудача обязана зафиксировать LOAD_FAULT. */
CHECK(load_state == (attempt == limit ? LOAD_FAULT : LOAD_RELOAD));
/* Завершает проверку всех разрешённых попыток текущего сеанса. */
}
/* Достаточное напряжение и повышение лимита сами по себе не снимают уже зафиксированную ошибку. */
LOAD_MAX_ATTEMPTS = limit + 1; tick(3000, 1, 30);
/* Счётчик остаётся прежним, аппаратный STOP и запрет разрешения сохраняются после изменения настройки. */
CHECK(test_starts == limit && load_attempts == limit && test_stop && !test_permission);
/* Диагностический блок версии 1 продолжает возвращать текущий счётчик в слове 5, независимо от лимита 0x7D. */
CHECK(Load_protection_prepare(3, 0x1300, 8, out, &error) == 8 && !error && out[5] == limit);
/* Снятие START обнуляет счётчик, но сохраняет лимит для следующего сеанса пуска. */
Commands = 0; tick(1000, 1, 30); CHECK(!load_attempts && LOAD_MAX_ATTEMPTS == (int)(limit + 1));
/* Значение 7 — последний сценарий; выход исключает повторение итерации с неизменным limit. */
if (limit == 7) break;
/* Завершает перебор проверяемых пользовательских лимитов. */
}
/* Завершает проверку обоих адресов УМП. */
}
/* Подготавливает первый неудачный пуск с разрешёнными пятью попытками. */
setup(5); Commands = 0x80; tick(1010, 1, 30);
/* Падение уже подтверждённого ЗПТ переводит автомат в секундный STOP перед повтором. */
load_count_ramp = time_dac / 6; tick(5, 1, 0); CHECK(load_state == LOAD_RELOAD);
/* Уменьшает предел до уже использованной одной попытки во время STOP, проверяя защиту перед следующим START. */
LOAD_MAX_ATTEMPTS = 1; tick(3000, 1, 30); CHECK(load_state == LOAD_FAULT && test_starts == 1);
/* Верхняя граница регистра сохраняется после подготовки автомата и не трактуется как отрицательный лимит. */
setup(6); LOAD_MAX_ATTEMPTS = 65535U; Setup_DAC_time(); WAKEpowse = 0;
/* Проверяет чтение максимального 16-битного значения без обнуления пользовательской настройки. */
CHECK((unsigned int)LOAD_MAX_ATTEMPTS == 65535U);
/* Доводит первый пуск до защитной паузы, затем моделирует последнюю попытку без 65534 циклов ожидания. */
Commands = 0x80; tick(1010, 1, 30); load_count_ramp = time_dac / 6; tick(5, 1, 0);
/* Значение 65534 соответствует числу ранее выданных START перед последней разрешённой попыткой. */
load_attempts = 65534U; tick(1000, 1, 30); CHECK(load_attempts == 65535U && test_starts == 2);
/* Последняя неудача фиксирует ошибку до возможного переполнения 16-битного счётчика. */
load_count_ramp = time_dac / 6; tick(5, 1, 0); tick(3000, 1, 30);
/* Проверяет удержание максимального счётчика, отсутствие дополнительного START и неизменность лимита. */
CHECK(load_state == LOAD_FAULT && load_attempts == 65535U && test_starts == 2 && (unsigned int)LOAD_MAX_ATTEMPTS == 65535U);
/* Возвращает успех после проверки сохранения лимита и пограничных сценариев его применения. */
return 0;
/* Завершает проверки настраиваемого количества попыток запуска. */
}
/* Запускает новые стартовые сценарии и прежние регрессии автомата на программных подменах периферии. */
int main(void) {
/* Объявляет out — данные out; error — ошибка; count — число; ramp — данные ramp; code — данные code. */
unsigned int out[8], error, count, ramp, code, stopped_at;
/* Сначала проверяет исправляемый штатный пуск с 6 мА, затем выполняет остальные регрессии защиты. */
CHECK(startup_test() == 0);
/* Дополнительно проверяет записываемый лимит 0x7D до прежних регрессий автомата нагрузки. */
CHECK(attempt_limit_test() == 0);
/* Вызывает setup с аргументами (5) в текущей последовательности операций. */
setup(5);
/* Boot ISR before parameters: no divide-by-zero and no GPIO start. */
/* Записывает Commands значением 0x80; tick(10, 1, 0); CHECK(!test_starts); слово команд, технологический регистр 127. */
Load_control_init(); Commands = 0x80; tick(10, 1, 0); CHECK(!test_starts);
/* Записывает WAKEpowse значением 0; данные WAKEpowse. */
Setup_DAC_time(); WAKEpowse = 0;
/* Вызывает tick с аргументами (10, 0, 0); CHECK(test_starts == 1 && test_permission) в текущей последовательности операций. */
tick(10, 0, 0); CHECK(test_starts == 1 && test_permission);
/* Вызывает CHECK с аргументами (LOAD_CAN_TIMEOUT == 600) в текущей последовательности операций. */
CHECK(LOAD_CAN_TIMEOUT == 600);
/* Wrong ZPT and masked slots never confirm freshness. */
/* Записывает Commands значением 0x80; слово команд, технологический регистр 127. */
setup(5); Commands = 0x80;
/* Вызывает Load_voltage_can. Принимает напряжение выбранной нагрузки из достоверных слов CAN и сбрасывает возраст только нужного измерения. */
Load_voltage_can(0x8000U | 8U, 200, 0, 0);
/* Вызывает Load_voltage_can. Принимает напряжение выбранной нагрузки из достоверных слов CAN и сбрасывает возраст только нужного измерения. */
Load_voltage_can(305U, 200, 0, 0); tick(10, 0, 0);
/* Вызывает CHECK с аргументами (!test_starts && (LOAD_STATUS & 2)) в текущей последовательности операций. */
CHECK(!test_starts && (LOAD_STATUS & 2));
/* Вызывает Load_voltage_can. Принимает напряжение выбранной нагрузки из достоверных слов CAN и сбрасывает возраст только нужного измерения. */
Load_voltage_can(0x2000U | 303U, 0, 0, 30);
/* Вызывает tick с аргументами (1, 0, 0); CHECK(test_starts == 1) в текущей последовательности операций. */
tick(1, 0, 0); CHECK(test_starts == 1);
/* Freeze current and code at timeout; unrelated exchange cannot unfreeze. */
/* Вызывает tick с аргументами (1000, 1, 30); tick(600, 0, 0) в текущей последовательности операций. */
tick(1000, 1, 30); tick(600, 0, 0);
/* Записывает ramp значением load_count_ramp; code = modbus[123]; данные ramp. */
ramp = load_count_ramp; code = modbus[123];
/* Вызывает tick с аргументами (2000, 0, 0); CHECK(load_count_ramp == ramp && (unsigned int)modbus[123] == code) в текущей последовательности операций. */
tick(2000, 0, 0); CHECK(load_count_ramp == ramp && (unsigned int)modbus[123] == code);
/* Вызывает CHECK с аргументами (test_permission && !test_stop && (LOAD_STATUS & 2)) в текущей последовательности операций. */
CHECK(test_permission && !test_stop && (LOAD_STATUS & 2));
/* Вызывает Load_voltage_can. Принимает напряжение выбранной нагрузки из достоверных слов CAN и сбрасывает возраст только нужного измерения. */
Load_voltage_can(0x8000U | 8U, 200, 0, 0); tick(10, 0, 0);
/* Вызывает CHECK с аргументами (load_count_ramp == ramp) в текущей последовательности операций. */
CHECK(load_count_ramp == ramp);
/* Вызывает tick с аргументами (10, 1, 30); CHECK(load_count_ramp > ramp) в текущей последовательности операций. */
tick(10, 1, 30); CHECK(load_count_ramp > ramp);
/* Exactly 30 V permits growth; 29 V fails strictly above 6 mA. */
/* Записывает Commands значением 0x80; tick(10, 1, 30); слово команд, технологический регистр 127. */
setup(6); Commands = 0x80; tick(10, 1, 30);
/* Записывает load_count_ramp значением time_dac / 6; tick(5, 1, 30); load число ramp. */
load_count_ramp = time_dac / 6; tick(5, 1, 30);
/* Вызывает CHECK с аргументами (load_state == LOAD_RUN && modbus[0x1C] >= 60) в текущей последовательности операций. */
CHECK(load_state == LOAD_RUN && modbus[0x1C] >= 60);
/* Вызывает tick с аргументами (5, 1, 29); CHECK(load_state == LOAD_RELOAD && test_stop && !test_permission) в текущей последовательности операций. */
tick(5, 1, 29); CHECK(load_state == LOAD_RELOAD && test_stop && !test_permission);
/* Вызывает CHECK с аргументами (!test_start && load_count_ramp == 0 && modbus[0x1C] == 40) в текущей последовательности операций. */
CHECK(!test_start && load_count_ramp == 0 && modbus[0x1C] == 40);
/* Записывает stopped_at значением test_last_stop_tick; данные stopped_at. */
CHECK(modbus[123] == DAC_min()); stopped_at = test_last_stop_tick;
/* Вызывает tick с аргументами (999, 1, 0); CHECK(test_starts == 1 && test_stop) в текущей последовательности операций. */
tick(999, 1, 0); CHECK(test_starts == 1 && test_stop);
/* Вызывает tick с аргументами (1, 1, 0); CHECK(test_starts == 2 && test_last_start_tick-stopped_at == 1000) в текущей последовательности операций. */
tick(1, 1, 0); CHECK(test_starts == 2 && test_last_start_tick-stopped_at == 1000);
/* Вызывает CHECK с аргументами (!test_stop && test_permission && !test_bad_order) в текущей последовательности операций. */
CHECK(!test_stop && test_permission && !test_bad_order);
/* Five total attempts, then a persistent fault; no sixth start. */
/* Повторяет или ожидает, пока выполняется while (load_state != LOAD_FAULT). */
while (load_state != LOAD_FAULT) {
/* Записывает load_count_ramp значением time_dac / 6; tick(5, 1, 0); load число ramp. */
load_count_ramp = time_dac / 6; tick(5, 1, 0);
/* Проверяет if (load_state == LOAD_RELOAD) tick(1000, 1, 0); последующий оператор выполняется только при истинном условии. */
if (load_state == LOAD_RELOAD) tick(1000, 1, 0);
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Вызывает CHECK с аргументами (test_starts == 5 && load_attempts == 5 && (LOAD_STATUS & 1)) в текущей последовательности операций. */
CHECK(test_starts == 5 && load_attempts == 5 && (LOAD_STATUS & 1));
/* Вызывает tick с аргументами (3000, 1, 200); CHECK(test_starts == 5 && test_stop && !test_permission) в текущей последовательности операций. */
tick(3000, 1, 200); CHECK(test_starts == 5 && test_stop && !test_permission);
/* Записывает Commands значением 0xC0; tick(10, 1, 200); CHECK(load_state == LOAD_FAULT); слово команд, технологический регистр 127. */
Commands = 0xC0; tick(10, 1, 200); CHECK(load_state == LOAD_FAULT);
/* Записывает Commands значением 0; tick(1000, 1, 200); CHECK(!(LOAD_STATUS & 1)); слово команд, технологический регистр 127. */
Commands = 0; tick(1000, 1, 200); CHECK(!(LOAD_STATUS & 1));
/* Записывает Commands значением 0x80; test_starts = 0; tick(10, 1, 200); CHECK(load_attempts == 1); слово команд, технологический регистр 127. */
Commands = 0x80; test_starts = 0; tick(10, 1, 200); CHECK(load_attempts == 1);
/* Manual reset dominates START; releasing it alone cannot start again. */
/* Записывает Commands значением 0xC0; tick(1, 1, 200); CHECK(test_stop && !test_permission); слово команд, технологический регистр 127. */
Commands = 0xC0; tick(1, 1, 200); CHECK(test_stop && !test_permission);
/* Записывает Commands значением 0x80; tick(1500, 1, 200); CHECK(test_starts == 1); слово команд, технологический регистр 127. */
Commands = 0x80; tick(1500, 1, 200); CHECK(test_starts == 1);
/* Versioned simulation writes are bounded, read-only fields reject writes. */
/* Записывает count значением Load_protection_prepare(3, 0x1300, 8, out, &error); число. */
count = Load_protection_prepare(3, 0x1300, 8, out, &error);
/* Вызывает CHECK с аргументами (count == 8 && !error && out[0] == 0x5550 && out[1] == 1) в текущей последовательности операций. */
CHECK(count == 8 && !error && out[0] == 0x5550 && out[1] == 1);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1303, 0, out, &error); CHECK(error == 3);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1304, 0, out, &error); CHECK(error == 2);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1302, 4, out, &error); CHECK(error == 3);
/* Записывает Commands значением 0x80; tick(10, 1, 200); слово команд, технологический регистр 127. */
setup(5); Commands = 0x80; tick(10, 1, 200);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1303, 20, out, &error); CHECK(!error);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1302, 1, out, &error); CHECK(!error);
/* Вызывает tick с аргументами (30, 1, 200); CHECK(LOAD_STATUS & 2) в текущей последовательности операций. */
tick(30, 1, 200); CHECK(LOAD_STATUS & 2);
/* Записывает ramp значением load_count_ramp; tick(100, 1, 200); CHECK(load_count_ramp == ramp); данные ramp. */
ramp = load_count_ramp; tick(100, 1, 200); CHECK(load_count_ramp == ramp);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1302, 0, out, &error);
/* Вызывает tick с аргументами (10, 1, 200); CHECK(!(LOAD_STATUS & 2) && load_count_ramp > ramp) в текущей последовательности операций. */
tick(10, 1, 200); CHECK(!(LOAD_STATUS & 2) && load_count_ramp > ramp);
/* Вызывает Load_protection_prepare. Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
Load_protection_prepare(6, 0x1302, 2, out, &error);
/* Записывает load_count_ramp значением time_dac / 6; tick(5, 1, 200); CHECK(load_state == LOAD_RELOAD); load число ramp. */
load_count_ramp = time_dac / 6; tick(5, 1, 200); CHECK(load_state == LOAD_RELOAD);
/* Calibration must not replace the forced 4 mA output during reload. */
/* Устанавливает биты Commands значением 0x200; DAC_cal() = 4095; tick(5, 1, 200); слово команд, технологический регистр 127. */
Commands |= 0x200; DAC_cal() = 4095; tick(5, 1, 200);
/* Вызывает CHECK с аргументами (modbus[123] == DAC_min() && modbus[0x1C] == 40) в текущей последовательности операций. */
CHECK(modbus[123] == DAC_min() && modbus[0x1C] == 40);
/* A calibration code preceding START must be replaced by 4 mA first. */
/* Записывает Commands значением 0x200; DAC_cal() = 4095; слово команд, технологический регистр 127. */
setup(5); Commands = 0x200; DAC_cal() = 4095;
/* Вызывает tick с аргументами (10, 1, 200); CHECK(modbus[123] == 4095 && !load_zero_sent) в текущей последовательности операций. */
tick(10, 1, 200); CHECK(modbus[123] == 4095 && !load_zero_sent);
/* Записывает Commands значением 0x280; tick(1, 1, 200); CHECK(!test_starts); слово команд, технологический регистр 127. */
Commands = 0x280; tick(1, 1, 200); CHECK(!test_starts);
/* Вызывает tick с аргументами (4, 1, 200); CHECK(!test_starts && modbus[123] == DAC_min()) в текущей последовательности операций. */
tick(4, 1, 200); CHECK(!test_starts && modbus[123] == DAC_min());
/* Вызывает tick с аргументами (1, 1, 200); CHECK(test_starts == 1) в текущей последовательности операций. */
tick(1, 1, 200); CHECK(test_starts == 1);
/* Timeout while STOP is held cannot initiate the pending retry. */
/* Начинает пуск с заводскими 6 мА и свежим нулевым ЗПТ, чтобы затем проверить исчезновение CAN во время STOP. */
setup(5); DAC_go = 6; Commands = 0x80; tick(10, 1, 0);
/* Даёт три секунды на реакцию ЗПТ после первой отправки 6 мА, затем проверяет потерю CAN во время защитного сброса. */
tick(3000, 1, 0);
/* Вызывает CHECK с аргументами (load_state == LOAD_RELOAD) в текущей последовательности операций. */
CHECK(load_state == LOAD_RELOAD);
/* Вызывает tick с аргументами (1500, 0, 0); CHECK(test_starts == 1 && test_stop) в текущей последовательности операций. */
tick(1500, 0, 0); CHECK(test_starts == 1 && test_stop);
/* Вызывает tick с аргументами (1, 1, 0); CHECK(test_starts == 2 && !test_stop) в текущей последовательности операций. */
tick(1, 1, 0); CHECK(test_starts == 2 && !test_stop);
/* Вызывает Load_control_init. Сбрасывает все переменные автомата нагрузки до разрешения прерываний; COFF не обнуляет всю .ebss. */
Load_control_init(); CHECK(!load_simulation);
/* Сообщает об успехе проверки реального автомата, включая новый старт 6 мА с выдержкой 3 секунды и прежние защитные сценарии. */
/* Сообщает о проверке рабочих исходников, настраиваемого лимита и прежних режимов защиты нагрузки. */
puts("PASS: production DAC control, startup, timeout, CAN, STOP ordering, writable attempt limit, simulation");
/* Завершает main и возвращает 0. */
return 0;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}