Перейти на компактные 12-словные записи v4 и сохранять 10 процентов банка после отключения. Добавить трёхсекундное ожидание роста ЗПТ и настраиваемый лимит пусков. Явно инициализировать состояние UART и гарантировать публикацию параметров EEPROM перед запуском Timer2. Сохранить воспроизводимые сборки, регрессионные проверки, документацию и обновлённые результаты сборки; исключить временные артефакты.
492 lines
46 KiB
C
492 lines
46 KiB
C
/* Двухбанковый регистратор событий нагрузки во внешней RAM. Русские пояснения сохранены в UTF-8. */
|
||
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
|
||
#include "DSP2833x_Device.h"
|
||
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
|
||
#include "filter_bat2.h"
|
||
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
|
||
#include "measure.h"
|
||
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
|
||
#include "package.h"
|
||
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
|
||
#include "RS485.h"
|
||
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
|
||
#include "message.h"
|
||
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
|
||
#include "peripher.h"
|
||
/* Подключает "DAC.h": выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
|
||
#include "DAC.h"
|
||
/* Подключает "ADC.h": настройка АЦП, обработка преобразований и первичная фильтрация измерений. */
|
||
#include "ADC.h"
|
||
/* Подключает "log_to_mem.h": двухбанковый регистратор событий нагрузки во внешней RAM. */
|
||
#include "log_to_mem.h"
|
||
|
||
/* Объявляет no_write — no запись. Начальное значение задаётся справа от знака равенства. */
|
||
int no_write = 0,
|
||
/* Записывает never_write значением 0; never запись. */
|
||
never_write = 0; // Флаги, чтобы не писать (если что)
|
||
|
||
/* Указание компилятору DATA_SECTION(logs_block,".logg");: размещение данных или настройка обработки объявлений. */
|
||
#pragma DATA_SECTION(logs_block,".logg");
|
||
/* Объявляет logs_block — выделенный массив внешней RAM для двух банков регистратора. */
|
||
unsigned int logs_block[0xFA00];
|
||
|
||
/* Объявляет Log — данные Log. */
|
||
LOG Log;
|
||
/* Объявляет flog — данные flog. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int flog=0;
|
||
|
||
// Очищение памати, где логи лежат
|
||
/* Обнуляет выделенный диапазон внешней RAM журнала и задаёт границы кольцевого буфера. */
|
||
void clear_mem()
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет i — данные i. */
|
||
unsigned long i;
|
||
|
||
/* Записывает Log.Start значением LOG_PAGE_START; данные Start. */
|
||
Log.Start = LOG_PAGE_START;
|
||
/* Записывает Log.Finis значением LOG_PAGE_START + LOG_PAGE_LEN; данные Finis. */
|
||
Log.Finis = LOG_PAGE_START + LOG_PAGE_LEN;
|
||
/* Записывает Log.Adres значением Log.Start; данные Adres. */
|
||
Log.Adres = Log.Start;
|
||
/* Записывает Log.Circl значением 0; данные Circl. */
|
||
Log.Circl = 0;
|
||
|
||
/* Цикл for (i=Log.Start; i<Log.Finis; i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for (i=Log.Start; i<Log.Finis; i++)
|
||
/* Записывает i значением 0; данные i. */
|
||
*(volatile int *)i = 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Two RAM banks: freeze after 10% of bank capacity is recorded after stop. */
|
||
/* Объявляет ump_state — данные ump_state; ump_count — число сохранённых точек в активном банке; ump_cursor — данные ump_cursor; ump_next — данные ump_next. volatile требует фактического чтения или записи при каждом доступе. */
|
||
static volatile unsigned int ump_state, ump_count, ump_cursor, ump_next;
|
||
/* Объявляет ump_period — период записи регистратора в миллисекундных тактах; ump_divider — ump делитель. volatile требует фактического чтения или записи при каждом доступе. Начальное значение задаётся справа от знака равенства. */
|
||
static volatile unsigned int ump_period = 20, ump_divider;
|
||
/* Объявляет ump_time — миллисекундное время регистратора; ump_sequence — ump последовательность. volatile требует фактического чтения или записи при каждом доступе. */
|
||
static volatile unsigned long ump_time, ump_sequence;
|
||
/* Объявляет ump_bank — индекс активного банка регистратора; ump_archive_bank — индекс замороженного банка, доступного для чтения. Начальное значение задаётся справа от знака равенства. */
|
||
static unsigned int ump_bank, ump_archive_bank = 1;
|
||
/* Объявляет ump_archive_count — ump archive число; ump_archive_next — данные ump_archive_next; ump_generation — номер смены архивного банка. */
|
||
static unsigned int ump_archive_count, ump_archive_next, ump_generation;
|
||
/* Объявляет ump_source — данные ump_source; ump_post — данные ump_post. */
|
||
static unsigned int ump_source, ump_post;
|
||
/* Задаёт UMP_POST_POINTS = (UMP_LOG_CAPACITY / 10U); число записей после STOP — десятая часть ёмкости банка. */
|
||
#define UMP_POST_POINTS (UMP_LOG_CAPACITY / 10U)
|
||
/* Замораживает заполненный банк и переключает рабочий банк, сохраняя доступный архив. */
|
||
static void ump_freeze(void);
|
||
/* Latest PM67 sums: register 306 (index 305), register 9 (index 8). */
|
||
/* Объявляет ump_pm67_voltage — данные ump_pm67_voltage. */
|
||
static unsigned int ump_pm67_voltage[2];
|
||
/* Объявляет ump_prev_commands — данные ump_prev_commands; ump_prev_inputs — данные ump_prev_inputs; ump_prev_outputs — данные ump_prev_outputs. */
|
||
static unsigned int ump_prev_commands, ump_prev_inputs, ump_prev_outputs;
|
||
|
||
/* Called once at boot, before enabling interrupts. TI COFF startup does
|
||
* not clear uninitialized globals in .ebss. Do not use for record restart:
|
||
* restart must preserve the archive, time and latest received voltages. */
|
||
/* Явно инициализирует оба банка регистратора до включения IRQ; повторный старт записи архив не стирает. */
|
||
void ump_log_init(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет i — данные i. */
|
||
unsigned int i;
|
||
/* Записывает ump_state значением 0; ump_count = 0; ump_cursor = 0; ump_next = 0; данные ump_state. */
|
||
ump_state = 0; ump_count = 0; ump_cursor = 0; ump_next = 0;
|
||
/* Записывает ump_period значением 20; ump_divider = 0; период записи регистратора в миллисекундных тактах. */
|
||
ump_period = 20; ump_divider = 0;
|
||
/* Записывает ump_time значением 0; ump_sequence = 0; миллисекундное время регистратора. */
|
||
ump_time = 0; ump_sequence = 0;
|
||
/* Записывает ump_bank значением 0; ump_archive_bank = 1; индекс активного банка регистратора. */
|
||
ump_bank = 0; ump_archive_bank = 1;
|
||
/* Записывает ump_archive_count значением 0; ump_archive_next = 0; ump_generation = 0; ump archive число. */
|
||
ump_archive_count = 0; ump_archive_next = 0; ump_generation = 0;
|
||
/* Записывает ump_source значением 0; ump_post = 0; данные ump_source. */
|
||
ump_source = 0; ump_post = 0;
|
||
/* Цикл for (i = 0; i < 2; i++) ump_pm67_voltage[i] = 0;; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for (i = 0; i < 2; i++) ump_pm67_voltage[i] = 0;
|
||
/* Записывает ump_prev_commands значением 0; ump_prev_inputs = 0; ump_prev_outputs = 0; данные ump_prev_commands. */
|
||
ump_prev_commands = 0; ump_prev_inputs = 0; ump_prev_outputs = 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Логические уровни входов платы нагрузки: физический ноль означает 1.
|
||
* Чтение GPIO непосредственно здесь позволяет записать вход до следующего
|
||
* обновления регистра Inputs в основном цикле. */
|
||
/* Читает активные входы START/STOP/разрешения непосредственно из GPIO с учётом полярности. */
|
||
static unsigned int ump_inputs(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Завершает ump_inputs и возвращает (!GpioDataRegs.GPADAT.bit.GPIO6) |. */
|
||
return (!GpioDataRegs.GPADAT.bit.GPIO6) |
|
||
/* Продолжает список аргументов, полей или выражение ((!GpioDataRegs.GPADAT.bit.GPIO8) << 1) |; порядок элементов сохраняется. */
|
||
((!GpioDataRegs.GPADAT.bit.GPIO8) << 1) |
|
||
/* Продолжает список аргументов, полей или выражение ((!GpioDataRegs.GPADAT.bit.GPIO11) << 2);; порядок элементов сохраняется. */
|
||
((!GpioDataRegs.GPADAT.bit.GPIO11) << 2);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* START/STOP активны единицей; RES_OUT_2 активен физическим нулём. */
|
||
/* Собирает фактические состояния GPIO выходов START/STOP/разрешения нагрузки. */
|
||
static unsigned int ump_outputs(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Завершает ump_outputs и возвращает GpioDataRegs.GPBDAT.bit.GPIO62 |. */
|
||
return GpioDataRegs.GPBDAT.bit.GPIO62 |
|
||
/* Продолжает список аргументов, полей или выражение (GpioDataRegs.GPBDAT.bit.GPIO58 << 1) |; порядок элементов сохраняется. */
|
||
(GpioDataRegs.GPBDAT.bit.GPIO58 << 1) |
|
||
/* Продолжает список аргументов, полей или выражение ((!GpioDataRegs.GPADAT.bit.GPIO3) << 2);; порядок элементов сохраняется. */
|
||
((!GpioDataRegs.GPADAT.bit.GPIO3) << 2);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Вызывается только внутри короткой критической секции. Все три источника
|
||
* записей (main, CAN ISR, timer ISR) используют одну блокировку IRQ с
|
||
* восстановлением прежнего состояния, включая вызовы из прерывания. */
|
||
/* Создаёт одну запись состояния: входы, выходы, команды, напряжения и параметры тока нагрузки. */
|
||
static void ump_capture(unsigned int reason)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет p — данные p. Хранит указатель на данные. volatile требует фактического чтения или записи при каждом доступе. */
|
||
volatile unsigned int *p;
|
||
/* Объявляет commands — данные commands; inputs — данные inputs; outputs — данные outputs. */
|
||
unsigned int commands, inputs, outputs;
|
||
/* Проверяет if (ump_state != 1 или Desk != dsk_LOAD или !READY) return; последующий оператор выполняется только при истинном условии. */
|
||
if (ump_state != 1 || Desk != dsk_LOAD || !READY) return;
|
||
/* Проверяет if (no_write или never_write); последующий оператор выполняется только при истинном условии. */
|
||
if (no_write || never_write) { ump_state = 3; return; }
|
||
/* Записывает commands значением Commands; данные commands. */
|
||
commands = Commands;
|
||
/* Записывает inputs значением ump_inputs(); outputs = ump_outputs(); данные inputs. */
|
||
inputs = ump_inputs(); outputs = ump_outputs();
|
||
/* Freeze only an actual running-to-stopped output transition.
|
||
* STOP is set before RES_OUT_2 is cleared in main; an interrupt can
|
||
* observe these writes separately, so require its level, not its edge.
|
||
* Repeated reset/STOP pulses while already stopped leave the archive. */
|
||
/* Проверяет if (!ump_post и (ump_prev_outputs & 4U) и !(outputs & 4U) и; последующий оператор выполняется только при истинном условии. */
|
||
if (!ump_post && (ump_prev_outputs & 4U) && !(outputs & 4U) &&
|
||
/* Продолжает список аргументов, полей или выражение (outputs & 2U)) {; порядок элементов сохраняется. */
|
||
(outputs & 2U)) {
|
||
/* Keep 90% including the trigger; reserve 10% for later records. */
|
||
/* Проверяет if (ump_count >= UMP_LOG_CAPACITY - UMP_POST_POINTS); последующий оператор выполняется только при истинном условии. */
|
||
if (ump_count >= UMP_LOG_CAPACITY - UMP_POST_POINTS)
|
||
/* Записывает ump_count значением UMP_LOG_CAPACITY - UMP_POST_POINTS - 1; число сохранённых точек в активном банке. */
|
||
ump_count = UMP_LOG_CAPACITY - UMP_POST_POINTS - 1;
|
||
/* Записывает ump_post значением UMP_POST_POINTS; данные ump_post. */
|
||
ump_post = UMP_POST_POINTS;
|
||
/* Устанавливает биты reason значением 0x100; данные reason. */
|
||
reason |= 0x100;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Записывает ump_prev_commands значением commands; ump_prev_inputs = inputs; ump_prev_outputs = outputs; данные ump_prev_commands. */
|
||
ump_prev_commands = commands; ump_prev_inputs = inputs; ump_prev_outputs = outputs;
|
||
/* Every stored point counts, including CAN and I/O, except the trigger. */
|
||
/* Проверяет if (ump_post и !(reason & 0x100) и --ump_post == 0) reason = 5; последующий оператор выполняется только при истинном условии. */
|
||
if (ump_post && !(reason & 0x100) && --ump_post == 0) reason = 5;
|
||
/* Записывает p значением logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS; данные p. */
|
||
p = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS;
|
||
/* Сохраняет 32-битное миллисекундное время младшим словом вперёд; это первые два слова записи v4. */
|
||
p[0] = (unsigned int)ump_time; p[1] = (unsigned int)(ump_time >> 16);
|
||
/* Событие сохраняет причину и метку отключения; от команд остаются только нужные дискретные пуск и сброс, биты 7/6. */
|
||
p[2] = reason; p[3] = commands & 0xC0U;
|
||
/* Оставляет логические уровни входов и выходов для графиков START, STOP, OMEGA и разрешения нагрузки. */
|
||
p[4] = inputs; p[5] = outputs;
|
||
/* Задание тока берётся из регистра 0x1C в единицах 0,1 мА; это расчётная величина, а не измерение физического тока. */
|
||
p[6] = modbus[0x1C];
|
||
/* Сохраняет оставшиеся выбранные начальную и конечную уставки в целых мА. */
|
||
p[7] = DAC_go; p[8] = DAC_stop;
|
||
/* Оставляет оба ЗПТ в вольтах: CAN-индекс 305 относится к ЗПТ1, индекс 8 — к ЗПТ2. */
|
||
p[9] = ump_pm67_voltage[0]; p[10] = ump_pm67_voltage[1];
|
||
/* Резервное нулевое слово делает длину записи чётной: служебный CAN передаёт по два 16-битных слова за фрагмент. */
|
||
p[11] = 0;
|
||
/* Изменяет счётчик в выражении ump_next++; на один для следующего шага. */
|
||
ump_next++;
|
||
/* Проверяет if (ump_next == UMP_LOG_CAPACITY) ump_next = 0; последующий оператор выполняется только при истинном условии. */
|
||
if (ump_next == UMP_LOG_CAPACITY) ump_next = 0;
|
||
/* Проверяет if (ump_count < UMP_LOG_CAPACITY) ump_count++; последующий оператор выполняется только при истинном условии. */
|
||
if (ump_count < UMP_LOG_CAPACITY) ump_count++;
|
||
/* Изменяет счётчик в выражении ump_sequence++; на один для следующего шага. */
|
||
ump_sequence++;
|
||
/* Проверяет if (reason == 5) ump_freeze(); последующий оператор выполняется только при истинном условии. */
|
||
if (reason == 5) ump_freeze();
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Завершённый банк больше не изменяется до следующего отключения.
|
||
* Номер поколения позволяет GUI обнаружить замену архива во время чтения. */
|
||
/* Замораживает заполненный банк и переключает рабочий банк, сохраняя доступный архив. */
|
||
static void ump_freeze(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает ump_archive_bank значением ump_bank; индекс замороженного банка, доступного для чтения. */
|
||
ump_archive_bank = ump_bank;
|
||
/* Записывает ump_archive_count значением ump_count; ump_archive_next = ump_next; ump archive число. */
|
||
ump_archive_count = ump_count; ump_archive_next = ump_next;
|
||
/* Изменяет счётчик в выражении ump_generation++; на один для следующего шага. */
|
||
ump_generation++;
|
||
/* Инвертирует биты ump_bank значением 1; индекс активного банка регистратора. */
|
||
ump_bank ^= 1;
|
||
/* Записывает ump_count значением 0; ump_next = 0; ump_post = 0; число сохранённых точек в активном банке. */
|
||
ump_count = 0; ump_next = 0; ump_post = 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Продвигает время регистратора в Timer1 и снимает записи с заданным периодом. */
|
||
void ump_log_tick(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет saved — данные saved. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int saved = __disable_interrupts();
|
||
/* Проверяет if (ump_state == 1); последующий оператор выполняется только при истинном условии. */
|
||
if (ump_state == 1) {
|
||
/* Изменяет счётчик в выражении ump_time++; на один для следующего шага. */
|
||
ump_time++;
|
||
/* Проверяет if (++ump_divider >= ump_period); последующий оператор выполняется только при истинном условии. */
|
||
if (++ump_divider >= ump_period) { ump_divider = 0; ump_capture(1); }
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
|
||
__restore_interrupts(saved);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Дополнительный снимок только при изменении команд, входов или выходов.
|
||
* Это не заменяет периодическую запись аналоговых величин в таймере. */
|
||
/* Обслуживает изменения дискретных входов и выходов из главного цикла. */
|
||
void ump_log_io(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет saved — данные saved. */
|
||
unsigned int saved;
|
||
/* Проверяет if (ump_state != 1 или Desk != dsk_LOAD) return; последующий оператор выполняется только при истинном условии. */
|
||
if (ump_state != 1 || Desk != dsk_LOAD) return;
|
||
/* Записывает saved значением __disable_interrupts(); данные saved. */
|
||
saved = __disable_interrupts();
|
||
/* Проверяет if (Commands != ump_prev_commands или ump_inputs() != ump_prev_inputs или; последующий оператор выполняется только при истинном условии. */
|
||
if (Commands != ump_prev_commands || ump_inputs() != ump_prev_inputs ||
|
||
/* Вызывает ump_outputs. Собирает фактические состояния GPIO выходов START/STOP/разрешения нагрузки. */
|
||
ump_outputs() != ump_prev_outputs) ump_capture(3);
|
||
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
|
||
__restore_interrupts(saved);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Вызывается после применения слов принятого CAN-кадра: снимок содержит
|
||
* новые команды, а также исходный адрес/маску и все три слова кадра. */
|
||
/* Обновляет последние CAN-данные и напряжения для следующего снимка регистратора. */
|
||
void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет saved — данные saved; i — данные i; address — адрес; mask — маска; data — данные. */
|
||
unsigned int saved, i, address, mask, data[3];
|
||
/* Проверяет if (Desk != dsk_LOAD) return; последующий оператор выполняется только при истинном условии. */
|
||
if (Desk != dsk_LOAD) return;
|
||
/* Записывает saved значением __disable_interrupts(); данные saved. */
|
||
saved = __disable_interrupts();
|
||
/* Записывает data[0] значением a; data[1] = b; data[2] = c; данные. */
|
||
data[0] = a; data[1] = b; data[2] = c;
|
||
/* Записывает address значением header & 0x1FFFU; адрес. */
|
||
address = header & 0x1FFFU;
|
||
/* Записывает mask значением 0x8000U; маска. */
|
||
mask = 0x8000U;
|
||
/* Track reception even while recording is stopped. Each mask bit
|
||
* refers to its own address, including disabled words in between. */
|
||
/* Цикл for (i = 0; i < 3; i++, address++, mask >>= 1) ; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for (i = 0; i < 3; i++, address++, mask >>= 1) {
|
||
/* Проверяет if (!(header & mask)) continue; последующий оператор выполняется только при истинном условии. */
|
||
if (!(header & mask)) continue;
|
||
/* Проверяет if (address == 305U) ump_pm67_voltage[0] = data[i]; последующий оператор выполняется только при истинном условии. */
|
||
if (address == 305U) ump_pm67_voltage[0] = data[i];
|
||
/* Проверяет if (address == 8U) ump_pm67_voltage[1] = data[i]; последующий оператор выполняется только при истинном условии. */
|
||
if (address == 8U) ump_pm67_voltage[1] = data[i];
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Проверяет if (ump_state != 1); последующий оператор выполняется только при истинном условии. */
|
||
if (ump_state != 1) { __restore_interrupts(saved); return; }
|
||
/* Вызывает ump_capture. Создаёт одну запись состояния: входы, выходы, команды, напряжения и параметры тока нагрузки. */
|
||
ump_capture(2);
|
||
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
|
||
__restore_interrupts(saved);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Регистрирует изменение слова команд после записи по последовательному интерфейсу. */
|
||
void ump_log_rs(void)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет saved — данные saved. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int saved = __disable_interrupts();
|
||
/* Вызывает ump_capture. Создаёт одну запись состояния: входы, выходы, команды, напряжения и параметры тока нагрузки. */
|
||
ump_capture(4);
|
||
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
|
||
__restore_interrupts(saved);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Управление журналом отделено от технологических команд: начало записи
|
||
* НЕ запускает УМП. Выбор архива не останавливает текущую запись. */
|
||
/* Применяет допустимые команды управления регистратором, сохраняя ограничения адресов. */
|
||
int ump_log_write(unsigned int address, unsigned int value)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет saved — данные saved; valid — данные valid. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int saved, valid = 1;
|
||
/* Записывает saved значением __disable_interrupts(); данные saved. */
|
||
saved = __disable_interrupts();
|
||
/* Проверяет if (address == UMP_LOG_BASE и value == 0); последующий оператор выполняется только при истинном условии. */
|
||
if (address == UMP_LOG_BASE && value == 0) {
|
||
/* Записывает ump_state значением 3; ump_post = 0; данные ump_state. */
|
||
ump_state = 3; ump_post = 0;
|
||
/* Проверяет else if (address == UMP_LOG_BASE и value == 1 и Desk == dsk_LOAD и READY и ump_state != 1); последующий оператор выполняется только при истинном условии. */
|
||
} else if (address == UMP_LOG_BASE && value == 1 && Desk == dsk_LOAD && READY && ump_state != 1) {
|
||
/* Записывает ump_count значением 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0; число сохранённых точек в активном банке. */
|
||
ump_count = 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0;
|
||
/* Записывает ump_source значением 0; данные ump_source. */
|
||
ump_source = 0;
|
||
/* Записывает ump_prev_commands значением Commands; данные ump_prev_commands. */
|
||
ump_prev_commands = Commands;
|
||
/* Записывает ump_prev_inputs значением ump_inputs(); ump_prev_outputs = ump_outputs(); данные ump_prev_inputs. */
|
||
ump_prev_inputs = ump_inputs(); ump_prev_outputs = ump_outputs();
|
||
/* Записывает no_write значением 0; never_write = 0; no запись. */
|
||
no_write = 0; never_write = 0;
|
||
/* Записывает ump_state значением 1; данные ump_state. */
|
||
ump_state = 1;
|
||
/* Вызывает ump_capture. Создаёт одну запись состояния: входы, выходы, команды, напряжения и параметры тока нагрузки. */
|
||
ump_capture(1);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Проверяет else if (address == UMP_LOG_BASE+1 и ump_state != 1 и value >= 1 и value <= 1000); последующий оператор выполняется только при истинном условии. */
|
||
else if (address == UMP_LOG_BASE+1 && ump_state != 1 && value >= 1 && value <= 1000)
|
||
/* Записывает ump_period значением value; период записи регистратора в миллисекундных тактах. */
|
||
ump_period = value;
|
||
/* Проверяет else if (address == UMP_LOG_BASE+2 и value < UMP_LOG_CAPACITY); последующий оператор выполняется только при истинном условии. */
|
||
else if (address == UMP_LOG_BASE+2 && value < UMP_LOG_CAPACITY)
|
||
/* Записывает ump_cursor значением value; данные ump_cursor. */
|
||
ump_cursor = value;
|
||
/* Проверяет else if (address == UMP_LOG_BASE+3 и value <= 1) ump_source = value; последующий оператор выполняется только при истинном условии. */
|
||
else if (address == UMP_LOG_BASE+3 && value <= 1) ump_source = value;
|
||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||
else valid = 0;
|
||
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
|
||
__restore_interrupts(saved);
|
||
/* Завершает ump_log_write и возвращает valid. */
|
||
return valid;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Преобразование хронологического индекса в физическую позицию кольца.
|
||
* Для архива сохранены собственные count/next, независимые от живого банка. */
|
||
/* Начинает функцию ump_word; назначение модуля — двухбанковый регистратор событий нагрузки во внешней RAM. */
|
||
static unsigned int ump_word(unsigned int archived, unsigned int record, unsigned int word)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет count — число; ump_count — число сохранённых точек в активном банке. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int count = archived ? ump_archive_count : ump_count;
|
||
/* Объявляет next — данные next; ump_next — данные ump_next. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int next = archived ? ump_archive_next : ump_next;
|
||
/* Объявляет bank — данные bank; ump_bank — индекс активного банка регистратора. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int bank = archived ? ump_archive_bank : ump_bank;
|
||
/* Объявляет slot — данные slot. */
|
||
unsigned int slot;
|
||
/* Проверяет if (record >= count) return 0; последующий оператор выполняется только при истинном условии. */
|
||
if (record >= count) return 0;
|
||
/* Записывает slot значением next + UMP_LOG_CAPACITY - count + record; данные slot. */
|
||
slot = next + UMP_LOG_CAPACITY - count + record;
|
||
/* Повторяет или ожидает, пока выполняется while (slot >= UMP_LOG_CAPACITY) slot -= UMP_LOG_CAPACITY;. */
|
||
while (slot >= UMP_LOG_CAPACITY) slot -= UMP_LOG_CAPACITY;
|
||
/* Завершает ump_word и возвращает logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word]. */
|
||
return logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word];
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Весь Modbus-блок читается вызывающим кодом под одной блокировкой IRQ.
|
||
* Поэтому timestamp/данные и заголовок онлайн-блока относятся к одному
|
||
* состоянию кольца, даже если в этот момент приходит новая CAN-команда. */
|
||
/* Проверяет область чтения регистратора и возвращает слова состояния либо архивной записи. */
|
||
unsigned int ump_log_read(unsigned int address)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет offset — данные offset; count — число. */
|
||
unsigned int offset, count;
|
||
/* Объявляет first — данные first. */
|
||
unsigned long first;
|
||
/* Вызывает switch с аргументами (address) { в текущей последовательности операций. */
|
||
switch (address) {
|
||
/* Ветвь выбора для UMP_LOG_BASE; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE: return 0x554D;
|
||
/* Ветвь выбора для UMP_LOG_BASE+1; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+1: return 4;
|
||
/* Ветвь выбора для UMP_LOG_BASE+2; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+2: return ump_source ? 3 : ump_state;
|
||
/* Ветвь выбора для UMP_LOG_BASE+3; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+3: return ump_source ? ump_archive_count : ump_count;
|
||
/* Ветвь выбора для UMP_LOG_BASE+4; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+4: return UMP_LOG_WORDS;
|
||
/* Ветвь выбора для UMP_LOG_BASE+5; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+5: return UMP_LOG_CAPACITY;
|
||
/* Ветвь выбора для UMP_LOG_BASE+6; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+6: return ump_period;
|
||
/* Ветвь выбора для UMP_LOG_BASE+7; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+7: return (unsigned int)ump_time;
|
||
/* Ветвь выбора для UMP_LOG_BASE+8; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+8: return (unsigned int)(ump_time >> 16);
|
||
/* Ветвь выбора для UMP_LOG_BASE+9; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+9: return Desk;
|
||
/* Ветвь выбора для UMP_LOG_BASE+10; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+10: return Mode;
|
||
/* Ветвь выбора для UMP_LOG_BASE+11; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+11: return (unsigned int)READY_FREQ;
|
||
/* Ветвь выбора для UMP_LOG_BASE+12; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+12: return ump_generation;
|
||
/* Ветвь выбора для UMP_LOG_BASE+13; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+13: return ump_archive_count;
|
||
/* Preserve the legacy millisecond status field as an upper estimate.
|
||
* Additional event records may finish the post interval sooner. */
|
||
/* Ветвь выбора для UMP_LOG_BASE+14; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+14:
|
||
/* Записывает first значением (unsigned long)ump_post * ump_period; данные first. */
|
||
first = (unsigned long)ump_post * ump_period;
|
||
/* Завершает ump_log_read и возвращает first > 65535UL ? 65535U : (unsigned int)first. */
|
||
return first > 65535UL ? 65535U : (unsigned int)first;
|
||
/* Ветвь выбора для UMP_LOG_BASE+15; выполняется при совпадении селектора switch. */
|
||
case UMP_LOG_BASE+15: return ump_state;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Проверяет if (address >= UMP_LOG_DATA и address < UMP_LOG_DATA+120 и (ump_source или ump_state != 1)); последующий оператор выполняется только при истинном условии. */
|
||
if (address >= UMP_LOG_DATA && address < UMP_LOG_DATA+120 && (ump_source || ump_state != 1)) {
|
||
/* Записывает offset значением address - UMP_LOG_DATA; данные offset. */
|
||
offset = address - UMP_LOG_DATA;
|
||
/* Завершает ump_log_read и возвращает ump_word(ump_source, ump_cursor + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS). */
|
||
return ump_word(ump_source, ump_cursor + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Последние UMP_LOG_LIVE_RECORDS записей для онлайн-графика, без остановки и без
|
||
* изменения курсора архивного чтения. Первые два слова — их номер. */
|
||
/* Проверяет if (address >= UMP_LOG_LIVE и address < UMP_LOG_LIVE+124); последующий оператор выполняется только при истинном условии. */
|
||
if (address >= UMP_LOG_LIVE && address < UMP_LOG_LIVE+124) {
|
||
/* Записывает count значением ump_count < UMP_LOG_LIVE_RECORDS ? ump_count : UMP_LOG_LIVE_RECORDS; число. */
|
||
count = ump_count < UMP_LOG_LIVE_RECORDS ? ump_count : UMP_LOG_LIVE_RECORDS;
|
||
/* Записывает first значением ump_sequence - count; данные first. */
|
||
first = ump_sequence - count;
|
||
/* Записывает offset значением address - UMP_LOG_LIVE; данные offset. */
|
||
offset = address - UMP_LOG_LIVE;
|
||
/* Проверяет if (offset == 0) return (unsigned int)first; последующий оператор выполняется только при истинном условии. */
|
||
if (offset == 0) return (unsigned int)first;
|
||
/* Проверяет if (offset == 1) return (unsigned int)(first >> 16); последующий оператор выполняется только при истинном условии. */
|
||
if (offset == 1) return (unsigned int)(first >> 16);
|
||
/* Проверяет if (offset == 2) return count; последующий оператор выполняется только при истинном условии. */
|
||
if (offset == 2) return count;
|
||
/* Проверяет if (offset == 3) return ump_generation; последующий оператор выполняется только при истинном условии. */
|
||
if (offset == 3) return ump_generation;
|
||
/* Уменьшает offset значением 4; данные offset. */
|
||
offset -= 4;
|
||
/* Проверяет if (offset / UMP_LOG_WORDS < count); последующий оператор выполняется только при истинном условии. */
|
||
if (offset / UMP_LOG_WORDS < count)
|
||
/* Завершает ump_log_read и возвращает ump_word(0, ump_count - count + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS). */
|
||
return ump_word(0, ump_count - count + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Завершает ump_log_read и возвращает 0. */
|
||
return 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|