Сократить запись логгера УМП до 12 слов формата v4
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
Текущая логика дискретов описана в [SIFU_START_STOP.md](SIFU_START_STOP.md):
|
||||
CAN-фронты обрабатываются при приёме, импульсы снимаются таймером, STOP
|
||||
имеет приоритет. Формат записи v2 и интерфейс SetGUI сохранены.
|
||||
имеет приоритет. Компактный формат записи v4 совпадает с исполнением 167.
|
||||
|
||||
## Назначение и работа оператора
|
||||
|
||||
@@ -13,8 +13,9 @@ CAN-фронты обрабатываются при приёме, импуль
|
||||
Общий RS-адрес 16 здесь не рекомендуется: ответ содержит собственный адрес,
|
||||
и SetGUI проверяет совпадение адресов. CAN-настройки: [PERIPH28335_CAN.md](PERIPH28335_CAN.md).
|
||||
|
||||
Перенесён протокол v2 из 167: 40 слов на запись, два банка по 800 записей.
|
||||
Существующий SetGUI понимает эту прошивку без изменений программы.
|
||||
Используется формат v4 из 167: 12 слов на запись вместо прежних 40;
|
||||
ёмкость исполнения 166 сохранена — два банка по 800 записей.
|
||||
Для чтения нужен SetGUI с поддержкой компактного формата v4, как для 167.
|
||||
Кнопки записи управляют регистратором; команду запуска УМП подаёт контроллер.
|
||||
|
||||
1. **Начать запись** включает только регистратор, не пуск УМП.
|
||||
@@ -45,7 +46,8 @@ EEPROM не используется: под отключением в этой
|
||||
## Память и точность
|
||||
|
||||
Использована существующая секция `.logg` по адресу 0x200000: 64000
|
||||
16-битных слов. Два банка по 800 записей × 40 слов занимают её целиком.
|
||||
16-битных слов. Два банка по 800 записей × 12 слов используют 19200 слов;
|
||||
размер выделенной секции сохранён. Одна запись занимает 24 байта вместо 80.
|
||||
Текущий банк кольцевой. При триггере сохраняются последние до 399 записей,
|
||||
добавляется событие отключения, оставшаяся половина банка отведена
|
||||
постинтервалу. При 20 мс это до примерно 8 секунд до отключения и 1 секунды
|
||||
@@ -61,7 +63,7 @@ EEPROM не используется: под отключением в этой
|
||||
одинаковую отметку; порядок сохраняется порядком записей. На перезапуске
|
||||
регистратора счётчик продолжает прежнюю шкалу, при перезагрузке платы — 0.
|
||||
|
||||
Онлайн-опрос возвращает три последних записи каждые 40 мс. Он не гарантирует
|
||||
Онлайн-опрос возвращает до десяти последних записей каждые 40 мс. Он не гарантирует
|
||||
передачу каждого события при высоком CAN-трафике, медленном UART или паузах
|
||||
GUI. Номера записей позволяют убрать дубликаты и явно показать пропуски.
|
||||
Полный сохранившийся фрагмент следует читать кнопкой архива. Частота 20 мс
|
||||
@@ -73,7 +75,12 @@ GUI. Номера записей позволяют убрать дублика
|
||||
EEPROM, выделения памяти или копирования целого банка. Реальную задержку
|
||||
прерываний и длительность критических секций нужно измерить на F28335.
|
||||
|
||||
## Состав записи: 40 слов
|
||||
## Состав записи v4: 12 слов
|
||||
|
||||
Состав и позиции полей совпадают с компактным логгером 167. Убраны сырые
|
||||
данные АЦП и CAN, ошибки, счётчики, код и калибровки ЦАП, состояние разгона
|
||||
и прочие дополнительные диагностические поля. Управление нагрузкой 166,
|
||||
ёмкость банка и секундный постинтервал отключения сохранены.
|
||||
|
||||
| Слова | Данные | Единицы/смысл |
|
||||
|---|---|---|
|
||||
@@ -81,33 +88,21 @@ EEPROM, выделения памяти или копирования целог
|
||||
| 2 | Событие | 1 период, 2 CAN RX, 3 изменение I/O, 4 RS-команда, 5 конец постинтервала |
|
||||
| 2, бит 8 | Триггер отключения | флаг поверх причины события |
|
||||
| 2, бит 9 | Усечён постинтервал | установлен в конечном снимке |
|
||||
| 3 | Commands / modbus[0x7F] | все 16 бит, в том числе пуск, сброс, инициализация и калибровка ЦАП |
|
||||
| 3 | Commands & 0xC0 | только пуск УМП (бит 7) и сброс УМП (бит 6) |
|
||||
| 4 | Входы OMEGA, Start_1, Res_in | биты 0,1,2, активный уровень приведён к 1 |
|
||||
| 5 | START_DPTB, STOP_DPTB, RES_OUT_2 | биты 0,1,2, активный уровень приведён к 1 |
|
||||
| 6 | IMPowse | остаток импульса, мс |
|
||||
| 7 | WAKEpowse | остаток инициализации, тики DAC_FREQ |
|
||||
| 8 | modbus[0x7B] | 12-битный код, переданный функцией dSEND в ЦАП |
|
||||
| 9 | modbus[0x1C] | расчётное задание в 0.1 мА; GUI/CSV переводит в мА |
|
||||
| 10–13 | sens_data[0..3] | измеренные сигналы, знаковое 16-битное значение в исходном масштабе |
|
||||
| 14–17 | modbus[0..3] | маски ошибок измерений |
|
||||
| 18 | CAN заголовок | адрес регистра в младших 13 битах и маска трёх слов в старших |
|
||||
| 19–21 | Три слова последнего принятого CAN-кадра | без преобразования |
|
||||
| 22 | Счётчик записанных CAN RX | младшие 16 бит |
|
||||
| 23 | CanTimeOutErrorTR | младшие 16 бит счётчика тайм-аутов CAN TX |
|
||||
| 24–25 | Фиксированные границы разгона 166 | 6 и 16 мА; это не регистры настройки |
|
||||
| 26–28 | DAC_min(), DAC_max(), DAC_cal() | коды калибровки и ручного задания ЦАП |
|
||||
| 29–30 | DAC_04, DAC_20 | значения соответствующих регистров |
|
||||
| 31–32 | count_load, time_dac | положение и длительность разгона в тиках |
|
||||
| 33–34 | Эффективные границы разгона 166 | 60 и 160 в 0.1 мА; GUI показывает 6 и 16 мА |
|
||||
| 35 | kod | целочисленное положение, используемое Anal_output |
|
||||
| 36–39 | adc_table_lem[0..3] | ADCRESULT2..5 после сдвига на 4, диапазон 0..4095 |
|
||||
| 6 | modbus[0x1C] | расчётное задание в 0.1 мА; GUI/CSV переводит в мА |
|
||||
| 7–8 | Фиксированные начальная и конечная уставки 166 | 6 и 16 мА; это не регистры настройки |
|
||||
| 9 | ЗПТ1: U1 + U2 | ПМ67, регистр 306 / нулевой CAN-индекс 305, В |
|
||||
| 10 | ЗПТ2: U3 + U4 | ПМ67, регистр 9 / нулевой CAN-индекс 8, В |
|
||||
| 11 | Резерв | всегда ноль; чётная длина нужна для парной передачи CAN |
|
||||
|
||||
**Отправленный код ЦАП не является измеренным током выхода.** В этом проекте
|
||||
не установлено, какой вход аппаратно измеряет ток ЦАП. При включённом
|
||||
**Расчётное задание тока не является измеренным током выхода.** При включённом
|
||||
`cCalibrDac` отправляется `DAC_cal()`, а расчётное задание 0x1C остаётся
|
||||
результатом алгоритма разгона. Для диагностики это различие сохранено.
|
||||
В 166 каналы «АЦП 0..3» берутся из `adc_table_lem`, обновляемой в режиме
|
||||
нагрузки. Таблица `adc_table_tpl` в этом режиме не обновляется и не используется.
|
||||
результатом алгоритма разгона. Сырой код ЦАП и каналы АЦП в запись v4 не входят.
|
||||
Напряжения обновляются по подтверждённым маской словам CAN даже при остановленной
|
||||
записи: первый снимок содержит последние принятые значения. До первого приёма
|
||||
они равны нулю; отдельного флага свежести в формате v4 нет.
|
||||
|
||||
Управляющая формула 166 сохранена: `sinus = 10/16 * count_load + 2/16 * time_dac`.
|
||||
Регулируемый разгон и ограничители 167 не переносились. Поля границ показывают
|
||||
@@ -128,9 +123,9 @@ FC03, 0x1000, 16 слов:
|
||||
|
||||
| Смещение | Значение |
|
||||
|---|---|
|
||||
| 0,1 | 0x554D, версия 2 |
|
||||
| 0,1 | 0x554D, версия 4 |
|
||||
| 2,3 | состояние и число записей выбранного источника |
|
||||
| 4,5 | 40 слов в записи, 800 записей в банке |
|
||||
| 4,5 | 12 слов в записи, 800 записей в банке |
|
||||
| 6 | период периодических снимков, мс |
|
||||
| 7,8 | счётчик времени, младшее/старшее слово |
|
||||
| 9,10 | Desk (требуется 6 / dsk_LOAD), Mode |
|
||||
@@ -148,15 +143,17 @@ FC06:
|
||||
- 0x1002: хронологический индекс первой записи окна 0..799;
|
||||
- 0x1003: источник окна, 0 — текущий остановленный банк, 1 — архив отключения.
|
||||
|
||||
FC03, 0x1010, до 120 слов: окно до трёх записей от установленного индекса.
|
||||
FC03, 0x1010, до 120 слов: окно до десяти записей от установленного индекса.
|
||||
Для CAN длина должна быть кратна 12 словам: 12, 24, ..., 120; прежние
|
||||
блоки v2 по 40 или 80 слов отклоняются как обрывающие компактную запись.
|
||||
Чтение текущего банка этим окном во время записи не выдаёт изменяющиеся
|
||||
данные. GUI сначала останавливает его; архив можно читать при работающем
|
||||
текущем банке. После всех блоков GUI повторно проверяет поколение архива;
|
||||
при замене во время чтения результат не подменяет предыдущий график.
|
||||
|
||||
FC03, 0x1100, ровно 124 слова: онлайн-блок. Слова 0,1 — 32-битный номер
|
||||
первой записи, 2 — число записей 0..3, 3 — поколение архива, далее до трёх
|
||||
записей по 40 слов. Неиспользованные слова равны нулю. Окно онлайн не
|
||||
первой записи, 2 — число записей 0..10, 3 — поколение архива, далее до десяти
|
||||
записей по 12 слов. Неиспользованные слова равны нулю. Окно онлайн не
|
||||
зависит от курсора/выбора архива. Разделение 0x1010 и 0x1100 предотвращает
|
||||
пересечение двух окон.
|
||||
|
||||
@@ -167,7 +164,14 @@ CRC и разбор стандартного ответа GUI использую
|
||||
|
||||
## Проверка и запуск
|
||||
|
||||
Перенесены регистратор и RS/CAN-доступ из коммитов 167 `df71922` и `a3633d8`.
|
||||
Для компактного формата v4 пройден host-тест настоящего `log_to_mem.c`
|
||||
с MSVC 14.30.30705. Модули `log_to_mem.c`, `ecan.c` и `message.c`
|
||||
скомпилированы TI C2000 22.6.0.LTS с COFF, FPU32 и O1 без ошибок.
|
||||
Полная линковка и обновление образов BIN/HEX для этой правки не выполнялись.
|
||||
|
||||
Первоначально регистратор и RS/CAN-доступ перенесены из коммитов 167
|
||||
`df71922` и `a3633d8`. Приведённые ниже результаты полной сборки относятся
|
||||
к исходному формату v2 до сокращения полей.
|
||||
Сборка всех 27 C/ASM-файлов и линковка TI C2000 22.6.1.LTS (Debug, COFF,
|
||||
FPU32, O1) прошли. Остались шесть прежних предупреждений в measure.c/peripher.c.
|
||||
В MAP: RAML0 занято 0x38D1 из 0x4000 слов, .ebss — 0xFA9 из 0x3000,
|
||||
@@ -176,8 +180,10 @@ FPU32, O1) прошли. Остались шесть прежних предуп
|
||||
Сборка проверки лежит вне репозитория, штатные файлы Bin не заменены.
|
||||
|
||||
Host-тест компилирует настоящий log_to_mem.c с подменой GPIO/IRQ.
|
||||
Проверяет кольцо, архив, переполнение постинтервала, онлайн-окно, CAN-протокол,
|
||||
готовность именно 166, фиксированные границы и четыре канала АЦП.
|
||||
Проверяет кольцо, архив, переполнение постинтервала, онлайн-окно из десяти
|
||||
12-словных записей, CAN-протокол v4, готовность именно 166, фиксированные
|
||||
уставки 6/16 мА, маску команд и получение ЗПТ из трёх позиций CAN-кадра.
|
||||
Сторожевые значения контролируют границу записи и разделение банков.
|
||||
Запуск из корня 166: `py -3 tests/ump_logger/run_test.py` (Clang/lld или MSVC
|
||||
в PATH); при необходимости передать `--compiler "полный путь к cl.exe"`.
|
||||
Тест не проверяет физические GPIO, тайминги прерываний и 16-битную ABI TI.
|
||||
@@ -186,7 +192,7 @@ Host-тест компилирует настоящий log_to_mem.c с подм
|
||||
начать запись → подать CAN-пуск → подать отключение → через секунду прочитать
|
||||
архив. Сверить START/STOP с физическими выходами и измерениями, повторить с
|
||||
разрывом RS/CAN. Проверить период 1 мс и задержки IRQ под нагрузкой.
|
||||
Тесты существующего SetGUI (`test_ump_logger.py`, `test_ump_logger_can.py`,
|
||||
Для первоначального формата v2 тесты SetGUI (`test_ump_logger.py`, `test_ump_logger_can.py`,
|
||||
`test_periph28335_tab.py`) в окружении Qt 5: **47 passed**. Проверены протокол,
|
||||
онлайн/архив, CAN-фрагменты, графики, курсоры и CSV.
|
||||
Проверка на устройстве не выполнялась.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
# Показывает русские комментарии изменённого исходника в CCS в сохранённой кодировке UTF-8.
|
||||
encoding//Source/Internal/peripher.c=UTF-8
|
||||
encoding//Debug/Libraries/subdir_rules.mk=UTF-8
|
||||
encoding//Debug/Libraries/subdir_vars.mk=UTF-8
|
||||
encoding//Debug/Source/External/v120/DSP2833x_common/source/subdir_rules.mk=UTF-8
|
||||
@@ -106,3 +104,8 @@ encoding//Debug/optimizerAssistant/opt_for_speed__5/subdir_vars.mk=UTF-8
|
||||
encoding//Debug/sources.mk=UTF-8
|
||||
encoding//Debug/subdir_rules.mk=UTF-8
|
||||
encoding//Debug/subdir_vars.mk=UTF-8
|
||||
encoding//Source/Internal/Include/log_to_mem.h=UTF-8
|
||||
encoding//Source/Internal/Include/ump_can_protocol.h=UTF-8
|
||||
encoding//Source/Internal/log_to_mem.c=UTF-8
|
||||
encoding//Source/Internal/peripher.c=UTF-8
|
||||
encoding/<project>=UTF-8
|
||||
|
||||
@@ -13,37 +13,76 @@ unsigned int adc_table_lem[4];
|
||||
__declspec(dllexport) int run_tests(void)
|
||||
{
|
||||
unsigned int i, generation, archived, reply[UMP_CAN_MAX_WORDS], error, length;
|
||||
/* Индексы перебирают все поля десяти записей онлайн-окна, проверяя отсутствие сдвига на старые 40 слов. */
|
||||
unsigned int record_index, word_index, block_words;
|
||||
unsigned long sequence;
|
||||
READY = 100;
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE, 1));
|
||||
READY = 0;
|
||||
/* Явная инициализация кэша гарантирует нулевые ЗПТ до первого принятого измерения. */
|
||||
CHECK(ump_pm67_voltage[0] == 0 && ump_pm67_voltage[1] == 0);
|
||||
/* Регистр 306 ПМ67 передаётся нулевым CAN-индексом 305 в первой позиции кадра. */
|
||||
ump_log_can(0x8000U | 305U, 321, 0, 0);
|
||||
/* Регистр 9 ПМ67 находится во второй позиции кадра с начальным индексом 7 и маской 0x4000. */
|
||||
ump_log_can(0x4000U | 7U, 0, 456, 0);
|
||||
/* Напряжения должны обновляться ещё до включения регистратора, чтобы первый снимок уже содержал измерения. */
|
||||
CHECK(ump_pm67_voltage[0] == 321 && ump_pm67_voltage[1] == 456 && ump_count == 0);
|
||||
/* Нулевая маска не разрешает первое слово и не должна подменять сохранённое напряжение. */
|
||||
ump_log_can(305U, 999, 0, 0);
|
||||
/* Индекс 306 не является индексом регистра 306: прошивка принимает именно нулевую нумерацию CAN. */
|
||||
ump_log_can(0x8000U | 306U, 999, 0, 0);
|
||||
/* Оба неверных заголовка обязаны оставить последнее корректное ЗПТ1 без изменения. */
|
||||
CHECK(ump_pm67_voltage[0] == 321);
|
||||
/* Третья позиция соответствует индексу 305 даже при пропущенных первых двух словах кадра. */
|
||||
ump_log_can(0x2000U | 303U, 0, 0, 123);
|
||||
/* Аналогично проверяет третью позицию для нулевого индекса 8 второго напряжения. */
|
||||
ump_log_can(0x2000U | 6U, 0, 0, 789);
|
||||
/* Последний принятый набор должен совпадать с ожидаемыми ЗПТ1/ЗПТ2 в вольтах. */
|
||||
CHECK(ump_pm67_voltage[0] == 123 && ump_pm67_voltage[1] == 789);
|
||||
adc_table_lem[0] = 2048; adc_table_lem[3] = 4095;
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+1, 0));
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+1, 1001));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE+1, 1));
|
||||
modbus[127] = 0x80;
|
||||
/* Дополнительные биты полного слова команд не должны попадать в компактное поле пуска/сброса v4. */
|
||||
modbus[127] = 0xAB80;
|
||||
/* Unrelated registers must not determine the fixed 166 ramp. */
|
||||
modbus[0x50] = 99; modbus[0x51] = 123;
|
||||
modbus[0x64] = 88; modbus[0x65] = 111;
|
||||
modbus[0x7B] = 1234; modbus[0x1C] = 160;
|
||||
/* Сторожевое значение во втором слоте обнаружит случайную запись старых полей за 12-словную границу. */
|
||||
logs_block[UMP_LOG_WORDS] = 0xA55A;
|
||||
/* Второй банк не должен затрагиваться заполнением и оборотом кольца первого банка. */
|
||||
logs_block[UMP_LOG_CAPACITY * UMP_LOG_WORDS] = 0x5AA5;
|
||||
CHECK(ump_log_write(UMP_LOG_BASE, 1));
|
||||
/* Число слов и чётная длина совпадают с компактным форматом исполнения 167. */
|
||||
CHECK(UMP_LOG_WORDS == 12 && 2UL * UMP_LOG_CAPACITY * UMP_LOG_WORDS <= LOG_PAGE_LEN);
|
||||
/* Первый снимок обязан содержать напряжения, принятые до запуска записи. */
|
||||
CHECK(ump_word(0, 0, 9) == 123 && ump_word(0, 0, 10) == 789);
|
||||
/* Нулевой резерв необходим для парной упаковки CAN и не должен содержать старый код ЦАП. */
|
||||
CHECK(ump_word(0, 0, 11) == 0 && logs_block[UMP_LOG_WORDS] == 0xA55A);
|
||||
/* В начале доступен один снимок, а оставшаяся часть 124-словного онлайн-окна заполнена нулями. */
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+2) == 1 && ump_log_read(UMP_LOG_LIVE+4+UMP_LOG_WORDS) == 0);
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE, 1));
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+1, 20));
|
||||
for (i=0; i<900; i++) ump_log_tick();
|
||||
CHECK(ump_count == UMP_LOG_CAPACITY);
|
||||
CHECK(ump_word(0, 0, 0) == 101);
|
||||
CHECK(ump_word(0, UMP_LOG_CAPACITY-1, 0) == 900);
|
||||
CHECK(ump_word(0, 0, 8) == 1234);
|
||||
CHECK(ump_word(0, 0, 24) == 6);
|
||||
CHECK(ump_word(0, 0, 25) == 16);
|
||||
CHECK(ump_word(0, 0, 36) == 2048);
|
||||
CHECK(ump_word(0, 0, 39) == 4095);
|
||||
/* После оборота кольца поле команд содержит только биты пуска и сброса, несмотря на посторонние биты 0xAB80. */
|
||||
CHECK(ump_word(0, 0, 3) == 0x80);
|
||||
/* Расчётное задание тока переместилось в слово 6 и сохраняет масштаб 0,1 мА. */
|
||||
CHECK(ump_word(0, 0, 6) == 160);
|
||||
/* Уставки исполнения 166 остаются фиксированными 6/16 мА независимо от технологических регистров 167. */
|
||||
CHECK(ump_word(0, 0, 7) == 6 && ump_word(0, 0, 8) == 16);
|
||||
/* При обороте кольца не теряются оба напряжения и не изменяется сторожевое значение следующего банка. */
|
||||
CHECK(ump_word(0, 0, 9) == 123 && ump_word(0, 0, 10) == 789 && logs_block[UMP_LOG_CAPACITY * UMP_LOG_WORDS] == 0x5AA5);
|
||||
/* Короткая CAN-команда должна остаться отдельным событием. */
|
||||
modbus[127] = 0x40;
|
||||
ump_log_can(0x807F, 0x40, 0, 0);
|
||||
CHECK(ump_post == 1000);
|
||||
CHECK(ump_word(0, ump_count-1, 2) == 0x102);
|
||||
CHECK(ump_word(0, ump_count-1, 18) == 0x807F);
|
||||
/* Событие CAN хранит выбранные команды в слове 3 вместо удалённого сырого заголовка в прежнем слове 18. */
|
||||
CHECK(ump_word(0, ump_count-1, 3) == 0x40);
|
||||
for (i=0; i<999; i++) ump_log_tick();
|
||||
CHECK(ump_generation == 0);
|
||||
ump_log_tick();
|
||||
@@ -59,8 +98,16 @@ __declspec(dllexport) int run_tests(void)
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 0) == archived);
|
||||
CHECK(ump_generation == generation);
|
||||
CHECK(ump_sequence == sequence + 200);
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+2) == 3);
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+4) == ump_time-2);
|
||||
/* Уменьшение записи увеличивает глубину онлайн-окна с трёх до десяти полных снимков. */
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+2) == UMP_LOG_LIVE_RECORDS && UMP_LOG_LIVE_RECORDS == 10);
|
||||
/* Первое онлайн-время относится к самому старому из десяти переданных снимков. */
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+4) == ump_time-UMP_LOG_LIVE_RECORDS+1);
|
||||
/* Сопоставляет каждую запись онлайн-окна с хронологическим чтением кольцевого банка. */
|
||||
for (record_index = 0; record_index < UMP_LOG_LIVE_RECORDS; record_index++)
|
||||
/* Проверяет все 12 слов, включая время, выбранные сигналы и нулевой резерв. */
|
||||
for (word_index = 0; word_index < UMP_LOG_WORDS; word_index++)
|
||||
/* Смещения должны заполнять ровно 120 полезных слов после четырёх служебных слов. */
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+4+record_index*UMP_LOG_WORDS+word_index) == ump_word(0, ump_count-UMP_LOG_LIVE_RECORDS+record_index, word_index));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE+3, 1));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE+2, UMP_LOG_CAPACITY-1));
|
||||
CHECK(ump_log_read(UMP_LOG_DATA) == archived);
|
||||
@@ -81,7 +128,27 @@ __declspec(dllexport) int run_tests(void)
|
||||
/* CAN читает те же регистры и формирует цельный снимок из 124 слов.
|
||||
* Запись по старым технологическим адресам через сервис запрещена. */
|
||||
length = ump_can_prepare(3, UMP_LOG_BASE, 16, reply, &error);
|
||||
CHECK(!error && length == 16 && reply[0] == 0x554D && reply[1] == 2);
|
||||
/* Служебный ответ должен объявлять версию v4, длину 12 слов и сохранённую ёмкость банка исполнения 166. */
|
||||
CHECK(!error && length == 16 && reply[0] == 0x554D && reply[1] == 4 && reply[4] == 12 && reply[5] == UMP_LOG_CAPACITY);
|
||||
/* Проверяет каждое разрешённое число целых компактных записей в архивном CAN-окне. */
|
||||
for (block_words = UMP_LOG_WORDS; block_words <= 120; block_words += UMP_LOG_WORDS) {
|
||||
/* Запрашивает от одной до десяти записей, не превышая полезную длину 120 слов. */
|
||||
length = ump_can_prepare(3, UMP_LOG_DATA, block_words, reply, &error);
|
||||
/* Все кратные длине записи запросы должны проходить без исключения Modbus. */
|
||||
CHECK(!error && length == block_words);
|
||||
} /* Завершает проверку допустимых размеров окна компактного архива. */
|
||||
/* Прежний блок v2 из 40 слов теперь обрывает запись v4 и должен отклоняться CAN-протоколом. */
|
||||
ump_can_prepare(3, UMP_LOG_DATA, 40, reply, &error);
|
||||
/* Исключение 2 сообщает о недопустимом диапазоне регистров. */
|
||||
CHECK(error == 2);
|
||||
/* Отклоняет пустой архивный запрос вместо его трактовки как успешного чтения. */
|
||||
ump_can_prepare(3, UMP_LOG_DATA, 0, reply, &error);
|
||||
/* Нулевая длина не содержит ни одной целой записи v4. */
|
||||
CHECK(error == 2);
|
||||
/* Блок из 11 записей уже превышает разрешённые 120 слов полезного окна. */
|
||||
ump_can_prepare(3, UMP_LOG_DATA, 132, reply, &error);
|
||||
/* Ограничение защищает буфер ответа от записи за его границами. */
|
||||
CHECK(error == 2);
|
||||
length = ump_can_prepare(3, UMP_LOG_LIVE, 124, reply, &error);
|
||||
CHECK(!error && length == 124);
|
||||
ump_can_prepare(3, UMP_LOG_LIVE, 126, reply, &error);
|
||||
|
||||
Reference in New Issue
Block a user