Сократить запись логгера УМП до 12 слов формата v4
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/* Контракт логгера с SetGUI: размер записи, версия и адреса.
|
||||
* Чтение целого блока защищается от IRQ на стороне RS/CAN обработчика.
|
||||
/* Контракт логгера с SetGUI: размер записи, версия и адреса.
|
||||
* Чтение целого блока защищается от IRQ на стороне RS/CAN обработчика.
|
||||
*/
|
||||
#ifndef _LOG_TO_MEM
|
||||
#define _LOG_TO_MEM
|
||||
@@ -8,11 +8,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Определениa длa работы логгера */
|
||||
/* Определениa длa работы логгера */
|
||||
#define LOG_PAGE_START 0x0200000
|
||||
#define LOG_PAGE_LEN 0xFA00
|
||||
|
||||
extern int no_write, never_write; // Флаги, чтобы не писать (если что)
|
||||
extern int no_write, never_write; // Флаги, чтобы не писать (если что)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -25,22 +25,25 @@ typedef struct
|
||||
|
||||
extern LOG Log;
|
||||
|
||||
/* Запись словa в памать, где логи лежат */
|
||||
/* Запись словa в памать, где логи лежат */
|
||||
#define Log_to_mem(x) *(int *)(Log.Adres++) = x
|
||||
|
||||
/* Проверка границы памати дла логов */
|
||||
/* Проверка границы памати дла логов */
|
||||
#define Test_mem_limit(x) if(Log.Adres > (Log.Finis - (x))) Log.Adres = Log.Start
|
||||
|
||||
/* Очистка памати (обнуление) */
|
||||
/* Очистка памати (обнуление) */
|
||||
void clear_mem();
|
||||
|
||||
/* Логгер УМП: отдельное адресное пространство Modbus, без изменения
|
||||
* 128 технологических регистров. Два банка по 800 записей:
|
||||
* текущий кольцевой журнал и зафиксированный фрагмент отключения. */
|
||||
/* Логгер УМП: отдельное адресное пространство Modbus, без изменения
|
||||
* 128 технологических регистров. Два банка по 800 записей:
|
||||
* текущий кольцевой журнал и зафиксированный фрагмент отключения. */
|
||||
#define UMP_LOG_BASE 0x1000U
|
||||
#define UMP_LOG_DATA 0x1010U
|
||||
#define UMP_LOG_WORDS 40U
|
||||
/* Формат v4 совпадает с 167: 12 слов по 16 бит содержат выбранные сигналы и нулевой резерв для парной передачи CAN. */
|
||||
#define UMP_LOG_WORDS 12U
|
||||
#define UMP_LOG_CAPACITY 800U
|
||||
/* Онлайн-окно вмещает 120 слов полезных данных: при формате v4 это десять полных записей. */
|
||||
#define UMP_LOG_LIVE_RECORDS (120U / UMP_LOG_WORDS)
|
||||
#define UMP_LOG_LIVE 0x1100U
|
||||
extern unsigned int ump_dac_ramp, ump_dac_duration, ump_dac_go10, ump_dac_stop10, ump_dac_position;
|
||||
void ump_log_tick(void);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/* Служебный CAN-протокол логгера УМП. Не использует адреса 0..127
|
||||
* технологического обмена. Формат полезных данных совместим с порядком
|
||||
* слов старого CAN: MDL (слова 1,2), затем MDH (маркер, слово 0).
|
||||
* Запрос: маркер 0x1F00, слово 0 = token:8 | function:8,
|
||||
* слова 1,2 = адрес расширения и число слов/записываемое значение.
|
||||
* Ответы: маркер 0x1F00 + номер фрагмента, слово 0 = token:8 | error:8,
|
||||
* слова 1,2 = два слова единого зафиксированного снимка.
|
||||
* Биты маски записи в заголовке запроса равны нулю: старая плата
|
||||
* игнорирует запрос, не изменяя технологические регистры. */
|
||||
/* Служебный CAN-протокол логгера УМП. Не использует адреса 0..127
|
||||
* технологического обмена. Формат полезных данных совместим с порядком
|
||||
* слов старого CAN: MDL (слова 1,2), затем MDH (маркер, слово 0).
|
||||
* Запрос: маркер 0x1F00, слово 0 = token:8 | function:8,
|
||||
* слова 1,2 = адрес расширения и число слов/записываемое значение.
|
||||
* Ответы: маркер 0x1F00 + номер фрагмента, слово 0 = token:8 | error:8,
|
||||
* слова 1,2 = два слова единого зафиксированного снимка.
|
||||
* Биты маски записи в заголовке запроса равны нулю: старая плата
|
||||
* игнорирует запрос, не изменяя технологические регистры. */
|
||||
#ifndef UMP_CAN_PROTOCOL_H
|
||||
#define UMP_CAN_PROTOCOL_H
|
||||
#include "log_to_mem.h"
|
||||
#define UMP_CAN_MARKER 0x1F00U
|
||||
#define UMP_CAN_MAX_WORDS 124U
|
||||
|
||||
/* Вызывающий код защищает весь снимок от IRQ. Функция не ждёт CAN и
|
||||
* не пишет за пределами reply[124]. Ошибки возвращаются отдельным кадром. */
|
||||
/* Вызывающий код защищает весь снимок от IRQ. Функция не ждёт CAN и
|
||||
* не пишет за пределами reply[124]. Ошибки возвращаются отдельным кадром. */
|
||||
static unsigned int ump_can_prepare(unsigned int function, unsigned int address,
|
||||
unsigned int value, unsigned int *reply, unsigned int *error)
|
||||
{
|
||||
@@ -22,7 +22,8 @@ static unsigned int ump_can_prepare(unsigned int function, unsigned int address,
|
||||
*error = 0;
|
||||
if (function == 3) {
|
||||
if (!((address == UMP_LOG_BASE && value == 16) ||
|
||||
(address == UMP_LOG_DATA && (value == 40 || value == 80 || value == 120)) ||
|
||||
/* Разрешает от одной до десяти целых 12-словных записей v4 в пределах 120 слов полезного окна CAN. */
|
||||
(address == UMP_LOG_DATA && value >= UMP_LOG_WORDS && value <= 120U && value % UMP_LOG_WORDS == 0U) ||
|
||||
(address == UMP_LOG_LIVE && value == 124))) *error = 2;
|
||||
else {
|
||||
for (i = 0; i < value; i++) reply[i] = ump_log_read(address+i);
|
||||
@@ -32,7 +33,7 @@ static unsigned int ump_can_prepare(unsigned int function, unsigned int address,
|
||||
if (address < UMP_LOG_BASE || address > UMP_LOG_BASE+3) *error = 2;
|
||||
else if (!ump_log_write(address, value)) *error = 3;
|
||||
} else *error = 1;
|
||||
/* Для записи возвращаем эхо адреса и значения, для ошибки — её контекст. */
|
||||
/* Для записи возвращаем эхо адреса и значения, для ошибки — её контекст. */
|
||||
reply[0] = address; reply[1] = value;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* Регистратор УМП во внешней памяти .logg: два банка по 800 записей
|
||||
* из 40 слов для SetGUI. Архив отключения не мешает дальнейшей записи.
|
||||
* Писатели из main/CAN/таймера защищаются короткими секциями IRQ
|
||||
* с восстановлением прежней маски. Архив не энергонезависимый.
|
||||
* clear_mem выполняется при запуске до включения прерываний.
|
||||
/* Регистратор УМП во внешней памяти .logg: два банка по 800 записей
|
||||
* из 12 слов формата v4 для SetGUI. Архив отключения не мешает дальнейшей записи.
|
||||
* Писатели из main/CAN/таймера защищаются короткими секциями IRQ
|
||||
* с восстановлением прежней маски. Архив не энергонезависимый.
|
||||
* clear_mem выполняется при запуске до включения прерываний.
|
||||
*/
|
||||
#include "DSP2833x_Device.h"
|
||||
#include "filter_bat2.h"
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "log_to_mem.h"
|
||||
|
||||
int no_write = 0,
|
||||
never_write = 0; // Флаги, чтобы не писать (если что)
|
||||
never_write = 0; // Изначально разрешает запись; установленный флаг прекращает сохранение снимков до следующего запуска регистратора.
|
||||
|
||||
#pragma DATA_SECTION(logs_block,".logg");
|
||||
unsigned int logs_block[0xFA00];
|
||||
@@ -24,7 +24,7 @@ unsigned int logs_block[0xFA00];
|
||||
LOG Log;
|
||||
unsigned int flog=0;
|
||||
|
||||
// Очищение памати, где логи лежат
|
||||
// Очищение памати, где логи лежат
|
||||
void clear_mem()
|
||||
{
|
||||
unsigned long i;
|
||||
@@ -37,27 +37,27 @@ void clear_mem()
|
||||
for (i=Log.Start; i<Log.Finis; i++)
|
||||
*(volatile int *)i = 0;
|
||||
}
|
||||
/* Два банка используют уже выделенную внешнюю RAM .logg (64000 слов).
|
||||
* Активный банк кольцевой. Через 1000 мс после команды отключения он
|
||||
* становится архивом, а запись продолжается во втором банке. Переключение
|
||||
* занимает постоянное время: копирования 30 тысяч слов под запретом IRQ нет.
|
||||
* Архив переживает разрыв RS-связи, но НЕ исчезновение питания платы. */
|
||||
/* Два банка используют уже выделенную внешнюю RAM .logg (64000 слов).
|
||||
* Активный банк кольцевой. Через 1000 мс после команды отключения он
|
||||
* становится архивом, а запись продолжается во втором банке. Переключение
|
||||
* занимает постоянное время: копирования 30 тысяч слов под запретом IRQ нет.
|
||||
* Архив переживает разрыв RS-связи, но НЕ исчезновение питания платы. */
|
||||
static volatile unsigned int ump_state, ump_count, ump_cursor, ump_next;
|
||||
static volatile unsigned int ump_period = 20, ump_divider;
|
||||
static volatile unsigned long ump_time, ump_sequence;
|
||||
static unsigned int ump_bank, ump_archive_bank = 1;
|
||||
static unsigned int ump_archive_count, ump_archive_next, ump_generation;
|
||||
static unsigned int ump_source, ump_post, ump_post_dropped;
|
||||
static unsigned int ump_can_header, ump_can_data[3], ump_can_count;
|
||||
/* Хранит последние ЗПТ1/ЗПТ2 в вольтах из регистров ПМ67 306/9; явные нули попадают в инициализацию COFF до первого CAN-кадра. */
|
||||
static unsigned int ump_pm67_voltage[2] = {0, 0};
|
||||
static unsigned int ump_prev_commands, ump_prev_inputs, ump_prev_outputs;
|
||||
extern int CanTimeOutErrorTR;
|
||||
/* Диагностика внутренних переменных разгона. Обновляется самим Load_runner,
|
||||
* не пересчитывает и не изменяет управляющий алгоритм. */
|
||||
/* Диагностика внутренних переменных разгона. Обновляется самим Load_runner,
|
||||
* не пересчитывает и не изменяет управляющий алгоритм. */
|
||||
unsigned int ump_dac_ramp, ump_dac_duration, ump_dac_go10, ump_dac_stop10, ump_dac_position;
|
||||
|
||||
/* Логические уровни входов платы нагрузки: физический ноль означает 1.
|
||||
* Чтение GPIO непосредственно здесь позволяет записать вход до следующего
|
||||
* обновления регистра Inputs в основном цикле. */
|
||||
/* Логические уровни входов платы нагрузки: физический ноль означает 1.
|
||||
* Чтение GPIO непосредственно здесь позволяет записать вход до следующего
|
||||
* обновления регистра Inputs в основном цикле. */
|
||||
static unsigned int ump_inputs(void)
|
||||
{
|
||||
return (!GpioDataRegs.GPADAT.bit.GPIO6) |
|
||||
@@ -65,7 +65,7 @@ static unsigned int ump_inputs(void)
|
||||
((!GpioDataRegs.GPADAT.bit.GPIO11) << 2);
|
||||
}
|
||||
|
||||
/* START/STOP активны единицей; RES_OUT_2 активен физическим нулём. */
|
||||
/* START/STOP активны единицей; RES_OUT_2 активен физическим нулём. */
|
||||
static unsigned int ump_outputs(void)
|
||||
{
|
||||
return GpioDataRegs.GPBDAT.bit.GPIO62 |
|
||||
@@ -73,62 +73,62 @@ static unsigned int ump_outputs(void)
|
||||
((!GpioDataRegs.GPADAT.bit.GPIO3) << 2);
|
||||
}
|
||||
|
||||
/* Вызывается только внутри короткой критической секции. Все три источника
|
||||
* записей (main, CAN ISR, timer ISR) используют одну блокировку IRQ с
|
||||
* восстановлением прежнего состояния, включая вызовы из прерывания. */
|
||||
/* Вызывается только внутри короткой критической секции. Все три источника
|
||||
* записей (main, CAN ISR, timer ISR) используют одну блокировку IRQ с
|
||||
* восстановлением прежнего состояния, включая вызовы из прерывания. */
|
||||
static void ump_capture(unsigned int reason)
|
||||
{
|
||||
volatile unsigned int *p;
|
||||
unsigned int i, commands;
|
||||
/* Указывает на начало одной 12-словной записи во внешней RAM; volatile сохраняет фактические обращения к памяти. */
|
||||
volatile unsigned int *record;
|
||||
/* Сохраняет полное слово команд для прежней логики триггера; в запись попадут только биты пуска и сброса. */
|
||||
unsigned int commands;
|
||||
if (ump_state != 1 || Desk != dsk_LOAD || READY) return;
|
||||
if (no_write || never_write) { ump_state = 3; return; }
|
||||
commands = Commands;
|
||||
/* Отключение: фронт cUMPreset (бит 6) либо спад cUMPstart (бит 7).
|
||||
* Повторные команды не сдвигают конец уже начатого постинтервала. */
|
||||
/* Отключение: фронт cUMPreset (бит 6) либо спад cUMPstart (бит 7).
|
||||
* Повторные команды не сдвигают конец уже начатого постинтервала. */
|
||||
if (!ump_post && (((commands & 0x40) && !(ump_prev_commands & 0x40)) ||
|
||||
(!(commands & 0x80) && (ump_prev_commands & 0x80)))) {
|
||||
/* Половину банка резервируем под постинтервал. Даже при периоде
|
||||
* 1 мс или шквале CAN событие отключения не вытесняется кольцом. */
|
||||
/* Половину банка резервируем под постинтервал. Даже при периоде
|
||||
* 1 мс или шквале CAN событие отключения не вытесняется кольцом. */
|
||||
if (ump_count >= UMP_LOG_CAPACITY/2) ump_count = UMP_LOG_CAPACITY/2-1;
|
||||
ump_post_dropped = 0;
|
||||
ump_post = 1000;
|
||||
reason |= 0x100;
|
||||
}
|
||||
/* Последнее место оставляем для снимка конца постинтервала. При
|
||||
* переполнении честно отмечаем усечение битом 0x200 в конечной записи. */
|
||||
/* Последнее место оставляем для снимка конца постинтервала. При
|
||||
* переполнении честно отмечаем усечение битом 0x200 в конечной записи. */
|
||||
if (ump_post && ump_count >= UMP_LOG_CAPACITY-1) {
|
||||
ump_post_dropped = 1;
|
||||
return;
|
||||
}
|
||||
if (reason == 5 && ump_post_dropped) reason |= 0x200;
|
||||
p = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS;
|
||||
p[0] = (unsigned int)ump_time; p[1] = (unsigned int)(ump_time >> 16);
|
||||
p[2] = reason; p[3] = commands;
|
||||
p[4] = ump_inputs(); p[5] = ump_outputs();
|
||||
p[6] = (unsigned int)IMPowse; p[7] = (unsigned int)WAKEpowse;
|
||||
p[8] = modbus[0x7B]; p[9] = modbus[0x1C];
|
||||
for (i = 0; i < 4; i++) { p[10+i] = sens_data[i]; p[14+i] = modbus[i]; }
|
||||
p[18] = ump_can_header;
|
||||
p[19] = ump_can_data[0]; p[20] = ump_can_data[1]; p[21] = ump_can_data[2];
|
||||
p[22] = ump_can_count; p[23] = CanTimeOutErrorTR;
|
||||
/* Исходные уставки — мА; эффективные уставки после ограничений — 0.1 мА.
|
||||
* p[8] — отправленный код, а p[9] — расчётное задание, НЕ измерение тока. */
|
||||
/* 166: fixed ramp endpoints; no configurable DAC_go/DAC_stop. */
|
||||
p[24] = 6; p[25] = 16;
|
||||
p[26] = DAC_min(); p[27] = DAC_max(); p[28] = DAC_cal();
|
||||
p[29] = DAC_04; p[30] = DAC_20;
|
||||
p[31] = ump_dac_ramp; p[32] = ump_dac_duration;
|
||||
p[33] = ump_dac_go10; p[34] = ump_dac_stop10; p[35] = ump_dac_position;
|
||||
for (i = 0; i < 4; i++) p[36+i] = adc_table_lem[i];
|
||||
ump_prev_commands = commands; ump_prev_inputs = p[4]; ump_prev_outputs = p[5];
|
||||
/* Выбирает слот банка по числу 16-битных слов записи; ёмкость 800 записей сохранена для исполнения 166. */
|
||||
record = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS;
|
||||
/* Слова 0/1 передают 32-битное время в миллисекундах младшей половиной вперёд, как в формате v4 исполнения 167. */
|
||||
record[0] = (unsigned int)ump_time; record[1] = (unsigned int)(ump_time >> 16);
|
||||
/* Слово 2 содержит событие, а маска 0xC0 оставляет в слове 3 только назначенные протоколом биты 7/6 пуска и сброса УМП. */
|
||||
record[2] = reason; record[3] = commands & 0xC0U;
|
||||
/* Слова 4/5 сохраняют фактические логические входы и выходы нагрузки для дискретных дорожек SetGUI. */
|
||||
record[4] = ump_inputs(); record[5] = ump_outputs();
|
||||
/* Слово 6 содержит расчётное задание тока регистра 0x1C в единицах 0,1 мА; физическое измерение тока здесь не выполняется. */
|
||||
record[6] = modbus[0x1C];
|
||||
/* Слова 7/8 содержат штатные фиксированные уставки разгона 166: начальные 6 мА и конечные 16 мА. */
|
||||
record[7] = 6; record[8] = 16;
|
||||
/* Слова 9/10 передают последние ЗПТ1/ЗПТ2 в вольтах из CAN-индексов 305/8, соответствующих регистрам ПМ67 306/9. */
|
||||
record[9] = ump_pm67_voltage[0]; record[10] = ump_pm67_voltage[1];
|
||||
/* Нулевое слово 11 дополняет запись до чётной длины: служебный CAN передаёт данные парами 16-битных слов. */
|
||||
record[11] = 0;
|
||||
/* Обновляет полные команды и фактические дискреты для обнаружения следующих событий, сохраняя алгоритм триггера 166. */
|
||||
ump_prev_commands = commands; ump_prev_inputs = record[4]; ump_prev_outputs = record[5];
|
||||
ump_next++;
|
||||
if (ump_next == UMP_LOG_CAPACITY) ump_next = 0;
|
||||
if (ump_count < UMP_LOG_CAPACITY) ump_count++;
|
||||
ump_sequence++;
|
||||
}
|
||||
|
||||
/* Завершённый банк больше не изменяется до следующего отключения.
|
||||
* Номер поколения позволяет GUI обнаружить замену архива во время чтения. */
|
||||
/* Завершённый банк больше не изменяется до следующего отключения.
|
||||
* Номер поколения позволяет GUI обнаружить замену архива во время чтения. */
|
||||
static void ump_freeze(void)
|
||||
{
|
||||
ump_archive_bank = ump_bank;
|
||||
@@ -152,8 +152,8 @@ void ump_log_tick(void)
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
/* Дополнительный снимок только при изменении команд, входов или выходов.
|
||||
* Это не заменяет периодическую запись аналоговых величин в таймере. */
|
||||
/* Дополнительный снимок только при изменении команд, входов или выходов.
|
||||
* Это не заменяет периодическую запись аналоговых величин в таймере. */
|
||||
void ump_log_io(void)
|
||||
{
|
||||
unsigned int saved;
|
||||
@@ -164,17 +164,34 @@ void ump_log_io(void)
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
/* Вызывается после применения слов принятого CAN-кадра: снимок содержит
|
||||
* новые команды, а также исходный адрес/маску и все три слова кадра. */
|
||||
/* Обновляет напряжения из принятых слов CAN даже до запуска записи;
|
||||
* активный регистратор дополнительно сохраняет событие приёма. */
|
||||
void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c)
|
||||
{
|
||||
unsigned int saved;
|
||||
if (ump_state != 1 || Desk != dsk_LOAD) return;
|
||||
/* Хранит прежнюю маску IRQ, индекс слова, текущий CAN-адрес, маску разрешения и три принятых 16-битных значения. */
|
||||
unsigned int saved, word_index, address, mask, can_words[3];
|
||||
/* Напряжения и журнал принадлежат плате нагрузки; другие аппаратные режимы их не обновляют. */
|
||||
if (Desk != dsk_LOAD) return;
|
||||
/* Исключает смешивание обновления напряжений с периодическим снимком таймера и восстанавливает прежние IRQ в конце. */
|
||||
saved = __disable_interrupts();
|
||||
ump_can_header = header;
|
||||
ump_can_data[0] = a; ump_can_data[1] = b; ump_can_data[2] = c;
|
||||
ump_can_count++;
|
||||
/* Располагает три принятых слова в том же порядке, в котором заголовок задаёт их последовательные адреса. */
|
||||
can_words[0] = a; can_words[1] = b; can_words[2] = c;
|
||||
/* Младшие 13 бит заголовка задают нулевой индекс первого регистра CAN; верхние три бита являются масками слов. */
|
||||
address = header & 0x1FFFU;
|
||||
/* Старший бит 0x8000 разрешает первое слово, далее используются биты 0x4000 и 0x2000. */
|
||||
mask = 0x8000U;
|
||||
/* Продвигает адрес и маску для всех трёх позиций, включая пропущенные слова, чтобы не перепутать регистры ПМ67. */
|
||||
for (word_index = 0; word_index < 3; word_index++, address++, mask >>= 1) {
|
||||
/* Не использует содержимое позиции, если соответствующий бит заголовка не подтверждает её передачу. */
|
||||
if (!(header & mask)) continue;
|
||||
/* Индекс 305 соответствует регистру 306 ПМ67: суммарное напряжение ЗПТ1 передаётся в целых вольтах. */
|
||||
if (address == 305U) ump_pm67_voltage[0] = can_words[word_index];
|
||||
/* Индекс 8 соответствует регистру 9 ПМ67: суммарное напряжение ЗПТ2 передаётся в целых вольтах. */
|
||||
if (address == 8U) ump_pm67_voltage[1] = can_words[word_index];
|
||||
} /* Завершает разбор трёх слов CAN после обновления только подтверждённых напряжений. */
|
||||
/* Сохраняет компактный снимок только при активной записи и готовности 166, которые проверяет ump_capture. */
|
||||
ump_capture(2);
|
||||
/* Возвращает исходную маску IRQ, в том числе при вызове из обработчика CAN. */
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
@@ -185,8 +202,8 @@ void ump_log_rs(void)
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
/* Управление журналом отделено от технологических команд: начало записи
|
||||
* НЕ запускает УМП. Выбор архива не останавливает текущую запись. */
|
||||
/* Управление журналом отделено от технологических команд: начало записи
|
||||
* НЕ запускает УМП. Выбор архива не останавливает текущую запись. */
|
||||
int ump_log_write(unsigned int address, unsigned int value)
|
||||
{
|
||||
unsigned int saved, valid = 1;
|
||||
@@ -211,8 +228,8 @@ int ump_log_write(unsigned int address, unsigned int value)
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* Преобразование хронологического индекса в физическую позицию кольца.
|
||||
* Для архива сохранены собственные count/next, независимые от живого банка. */
|
||||
/* Преобразование хронологического индекса в физическую позицию кольца.
|
||||
* Для архива сохранены собственные count/next, независимые от живого банка. */
|
||||
static unsigned int ump_word(unsigned int archived, unsigned int record, unsigned int word)
|
||||
{
|
||||
unsigned int count = archived ? ump_archive_count : ump_count;
|
||||
@@ -225,16 +242,17 @@ static unsigned int ump_word(unsigned int archived, unsigned int record, unsigne
|
||||
return logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word];
|
||||
}
|
||||
|
||||
/* Весь Modbus-блок читается вызывающим кодом под одной блокировкой IRQ.
|
||||
* Поэтому timestamp/данные и заголовок онлайн-блока относятся к одному
|
||||
* состоянию кольца, даже если в этот момент приходит новая CAN-команда. */
|
||||
/* Весь Modbus-блок читается вызывающим кодом под одной блокировкой IRQ.
|
||||
* Поэтому timestamp/данные и заголовок онлайн-блока относятся к одному
|
||||
* состоянию кольца, даже если в этот момент приходит новая CAN-команда. */
|
||||
unsigned int ump_log_read(unsigned int address)
|
||||
{
|
||||
unsigned int offset, count;
|
||||
unsigned long first;
|
||||
switch (address) {
|
||||
case UMP_LOG_BASE: return 0x554D;
|
||||
case UMP_LOG_BASE+1: return 2;
|
||||
/* Версия 4 сообщает SetGUI о 12-словной записи, исключая её ошибочный разбор как прежних 40 слов v2. */
|
||||
case UMP_LOG_BASE+1: return 4;
|
||||
case UMP_LOG_BASE+2: return ump_source ? 3 : ump_state;
|
||||
case UMP_LOG_BASE+3: return ump_source ? ump_archive_count : ump_count;
|
||||
case UMP_LOG_BASE+4: return UMP_LOG_WORDS;
|
||||
@@ -254,10 +272,11 @@ unsigned int ump_log_read(unsigned int address)
|
||||
offset = address - UMP_LOG_DATA;
|
||||
return ump_word(ump_source, ump_cursor + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
|
||||
}
|
||||
/* Последние три записи для онлайн-графика, без остановки и без
|
||||
* изменения курсора архивного чтения. Первые два слова — их номер. */
|
||||
/* Последние десять записей для онлайн-графика, без остановки и без
|
||||
* изменения курсора архивного чтения. Первые два слова — их номер. */
|
||||
if (address >= UMP_LOG_LIVE && address < UMP_LOG_LIVE+124) {
|
||||
count = ump_count < 3 ? ump_count : 3;
|
||||
/* Ограничивает число целых записей ёмкостью 120-словного окна: формат v4 позволяет передать до десяти снимков. */
|
||||
count = ump_count < UMP_LOG_LIVE_RECORDS ? ump_count : UMP_LOG_LIVE_RECORDS;
|
||||
first = ump_sequence - count;
|
||||
offset = address - UMP_LOG_LIVE;
|
||||
if (offset == 0) return (unsigned int)first;
|
||||
|
||||
Reference in New Issue
Block a user