Перейти на компактные 12-словные записи v4 и сохранять 10 процентов банка после отключения. Добавить трёхсекундное ожидание роста ЗПТ и настраиваемый лимит пусков. Явно инициализировать состояние UART и гарантировать публикацию параметров EEPROM перед запуском Timer2. Сохранить воспроизводимые сборки, регрессионные проверки, документацию и обновлённые результаты сборки; исключить временные артефакты.
690 lines
54 KiB
C
690 lines
54 KiB
C
/* Обработка Modbus, заводские параметры и сохранение настроек. Русские пояснения сохранены в UTF-8. */
|
||
/* Подключает "eeprom_config.h": выбор профиля физически установленной EEPROM при сборке. */
|
||
#include "eeprom_config.h"
|
||
/* Подключает "include/balsam167_eeprom_block.h": настройки и интерфейс balsam167_eeprom_block. */
|
||
#include "include/balsam167_eeprom_block.h"
|
||
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
|
||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
|
||
#include "package.h"
|
||
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
|
||
#include "RS485.h"
|
||
/* Подключает "crc16.h": таблицы и функции вычисления контрольных сумм CRC. */
|
||
#include "crc16.h"
|
||
/* Подключает "cntrl_adr.h": собственный и универсальный адрес устройства. */
|
||
#include "cntrl_adr.h"
|
||
/* Подключает "bios_dsp.h": коды и объявления команд последовательного загрузчика. */
|
||
#include "bios_dsp.h"
|
||
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
|
||
#include "message.h"
|
||
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
|
||
#include "filter_bat2.h"
|
||
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
|
||
#include "measure.h"
|
||
|
||
|
||
/* Подключает "ADC.h": настройка АЦП, обработка преобразований и первичная фильтрация измерений. */
|
||
#include "ADC.h"
|
||
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
|
||
#include "peripher.h"
|
||
|
||
/* Подключает "ecan.h": штатный eCAN и отдельный служебный обмен УМП/GAS. */
|
||
#include "ecan.h"
|
||
/* Подключает "pulto.h": обмен и индикация пульта. */
|
||
#include "pulto.h"
|
||
/* Подключает "spise2p.h": драйвер SPI EEPROM, адресация, страницы и автомат завершения операций. */
|
||
#include "spise2p.h"
|
||
|
||
/* Подключает "caliber.h": заводские калибровочные значения датчиков. */
|
||
#include "caliber.h"
|
||
/* Подключает "log_to_mem.h": двухбанковый регистратор событий нагрузки во внешней RAM. */
|
||
#include "log_to_mem.h"
|
||
/* Подключает "DAC.h": выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
|
||
#include "DAC.h"
|
||
/* Подключает "ump_tms28335.h": настройки и интерфейс ump_tms28335. */
|
||
#include "ump_tms28335.h"
|
||
/* Подключает "gas167.h": дополнительная карта GAS 167/v1 только для новой EEPROM M95M02. */
|
||
#include "gas167.h"
|
||
/* Подключает "include/balsam167_eeprom_layout.h": настройки и интерфейс balsam167_eeprom_layout. */
|
||
#include "include/balsam167_eeprom_layout.h"
|
||
/* Условие компиляции (ANSWER_LEN + 1) != BALSAM167_EEPROM_PARAM_WORDS: выбранный блок включается в текущий вариант прошивки. */
|
||
#if (ANSWER_LEN + 1) != BALSAM167_EEPROM_PARAM_WORDS
|
||
/* Останавливает сборку при недопустимой конфигурации: EEPROM_parameter_reservation_must_match_ANSWER_LEN. */
|
||
#error EEPROM_parameter_reservation_must_match_ANSWER_LEN
|
||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||
#endif
|
||
|
||
/* Объявляет modbus — массив технологических регистров; слово int на C28x занимает 16 бит. */
|
||
int modbus[ANSWER_LEN+1];
|
||
/* Объявляет param — данные param. */
|
||
unsigned int param[ANSWER_LEN+1];
|
||
|
||
/* Заполняет регистры заводскими значениями; для LOAD задаёт тайм-аут свежести CAN 2000 мс. Значение 600 мс применяется отдельно при восстановлении недопустимого параметра. */
|
||
void Default_params()
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет i — данные i; def — данные def. */
|
||
unsigned int i,def;
|
||
|
||
/* Объявляет shkf_lo_edge — данные shkf_lo_edge. Начальное значение задаётся справа от знака равенства. */
|
||
int shkf_lo_edge[] = {300, // 380
|
||
/* Элемент постоянной таблицы 300,; порядок значений совпадает с порядком индексов потребителя. */
|
||
300, // 38O
|
||
/* Элемент постоянной таблицы 0,; порядок значений совпадает с порядком индексов потребителя. */
|
||
0, // 0
|
||
/* Элемент постоянной таблицы 0,; порядок значений совпадает с порядком индексов потребителя. */
|
||
0, // 0
|
||
/* Элемент постоянной таблицы 15,; порядок значений совпадает с порядком индексов потребителя. */
|
||
15, // 31
|
||
/* Элемент постоянной таблицы 22,; порядок значений совпадает с порядком индексов потребителя. */
|
||
22, // 27
|
||
/* Элемент постоянной таблицы 20,; порядок значений совпадает с порядком индексов потребителя. */
|
||
20, // 24
|
||
/* Элемент постоянной таблицы 10,; порядок значений совпадает с порядком индексов потребителя. */
|
||
10, // 15
|
||
/* Элемент постоянной таблицы 60};; порядок значений совпадает с порядком индексов потребителя. */
|
||
60}; // AD
|
||
|
||
/* Объявляет bright — данные bright. Начальное значение задаётся справа от знака равенства. */
|
||
int bright[] = {10,8,6,8,6,8};
|
||
|
||
/* Цикл for(i=0;i<ANSWER_LEN;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<ANSWER_LEN;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает Modbus[i].all значением 0; представление регистра целым словом без разбиения на битовые поля. */
|
||
Modbus[i].all = 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Записывает LastMode значением Mode; последний режим платы, технологический регистр 126. */
|
||
LastMode = Mode;
|
||
|
||
/* Проверяет if(Desk == dsk_EPLT); последующий оператор выполняется только при истинном условии. */
|
||
if(Desk == dsk_EPLT)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает Cancount[m_FAST] значением 2; данные Cancount. */
|
||
Cancount[m_FAST] = 2; // пауза между посылками CAN
|
||
|
||
/* Цикл for(i=0;i<6;i++) Bright[i] = bright[i];; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<6;i++) Bright[i] = bright[i];
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||
else
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает Cancount[m_FAST] значением 10; данные Cancount. */
|
||
Cancount[m_FAST] = 10; // пауза между посылками CAN
|
||
/* Записывает Brightness значением 8; данные Brightness. */
|
||
Brightness = 8;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Записывает Cancount[m_SLOW] значением 101; данные Cancount. */
|
||
Cancount[m_SLOW] = 101; // пауза между посылками CAN
|
||
|
||
/* Проверяет if(Owen) Owncount = 20; последующий оператор выполняется только при истинном условии. */
|
||
if(Owen) Owncount = 20; // пауза между опросами OWEN
|
||
|
||
/* Проверяет if(Kalibro); последующий оператор выполняется только при истинном условии. */
|
||
if(Kalibro)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Включает следующий блок только при определённом символе CALIB_RS. */
|
||
#ifdef CALIB_RS
|
||
/* Записывает def значением Mode-1; данные def. */
|
||
def = Mode-1;
|
||
/* Проверяет if(Mode>adr_PULT) def--; последующий оператор выполняется только при истинном условии. */
|
||
if(Mode>adr_PULT) def--;
|
||
/* Выбирает альтернативный блок текущего условия компиляции. */
|
||
#else
|
||
/* Записывает def значением Mode-3; данные def. */
|
||
def = Mode-3;
|
||
/* Проверяет if(Mode==adr_SHKF) def=4; последующий оператор выполняется только при истинном условии. */
|
||
if(Mode==adr_SHKF) def=4;
|
||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||
#endif
|
||
/* Цикл for(i=0;i<8;i++) Caliber[i] = def_cal[def][i];; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<8;i++) Caliber[i] = def_cal[def][i];
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Проверяет if(Desk == dsk_COMM); последующий оператор выполняется только при истинном условии. */
|
||
if(Desk == dsk_COMM)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Цикл for(i=0;i<TPL_POW*2+Owen;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<TPL_POW*2+Owen;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает sens_hi_edge[i] значением 70; данные sens_hi_edge. */
|
||
sens_hi_edge[i] = 70;
|
||
/* Записывает sens_lo_edge[i] значением 60; данные sens_lo_edge. */
|
||
sens_lo_edge[i] = 60;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
} }
|
||
|
||
/* Проверяет if(Desk==dsk_BKSD); последующий оператор выполняется только при истинном условии. */
|
||
if(Desk==dsk_BKSD)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Цикл for(i=0;i<6;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<6;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает sens_hi_edge[i] значением 170; данные sens_hi_edge. */
|
||
sens_hi_edge[i] = 170;
|
||
/* Записывает sens_lo_edge[i] значением 150; данные sens_lo_edge. */
|
||
sens_lo_edge[i] = 150;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Цикл for(i=6;i<8;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=6;i<8;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает sens_hi_edge[i] значением 115; данные sens_hi_edge. */
|
||
sens_hi_edge[i] = 115;
|
||
/* Записывает sens_lo_edge[i] значением 105; данные sens_lo_edge. */
|
||
sens_lo_edge[i] = 105;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
} }
|
||
|
||
/* Проверяет if(Desk==dsk_BKST); последующий оператор выполняется только при истинном условии. */
|
||
if(Desk==dsk_BKST)
|
||
/* Цикл for(i=0;i<TPL_TRN*2;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<TPL_TRN*2;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает sens_hi_edge[i] значением 70; данные sens_hi_edge. */
|
||
sens_hi_edge[i] = 70;
|
||
/* Записывает sens_lo_edge[i] значением 60; данные sens_lo_edge. */
|
||
sens_lo_edge[i] = 60;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Проверяет if(Mode==adr_SHKF); последующий оператор выполняется только при истинном условии. */
|
||
if(Mode==adr_SHKF)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Цикл for(i=0;i<15;i++) sens_lo_edge[i] = shkf_lo_edge[sens_type[i]];; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<15;i++) sens_lo_edge[i] = shkf_lo_edge[sens_type[i]];
|
||
|
||
/* Записывает sens_hi_edge[13] значением 70; данные sens_hi_edge. */
|
||
sens_hi_edge[13] = 70;
|
||
/* Записывает sens_hi_edge[14] значением 70; данные sens_hi_edge. */
|
||
sens_hi_edge[14] = 70;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Проверяет if(Desk==dsk_LOAD); последующий оператор выполняется только при истинном условии. */
|
||
if(Desk==dsk_LOAD)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает sens_hi_edge[0] значением 420; данные sens_hi_edge. */
|
||
sens_hi_edge[0] = 420;
|
||
/* Записывает sens_hi_edge[1] значением 420; данные sens_hi_edge. */
|
||
sens_hi_edge[1] = 420;
|
||
/* Записывает sens_hi_edge[2] значением 900; данные sens_hi_edge. */
|
||
sens_hi_edge[2] = 900;
|
||
/* Записывает sens_hi_edge[3] значением 900; данные sens_hi_edge. */
|
||
sens_hi_edge[3] = 900;
|
||
/* Записывает sens_lo_edge[0] значением 300; данные sens_lo_edge. */
|
||
sens_lo_edge[0] = 300;
|
||
/* Записывает sens_lo_edge[1] значением 300; данные sens_lo_edge. */
|
||
sens_lo_edge[1] = 300;
|
||
/* Записывает sens_lo_edge[2] значением 800; данные sens_lo_edge. */
|
||
sens_lo_edge[2] = 800;
|
||
/* Записывает sens_lo_edge[3] значением 800; данные sens_lo_edge. */
|
||
sens_lo_edge[3] = 800;
|
||
|
||
/* Записывает DAC_20 значением Caliber[6]; ЦАП 20. */
|
||
DAC_20 = Caliber[6];
|
||
/* Записывает DAC_04 значением Caliber[7]; ЦАП 04. */
|
||
DAC_04 = Caliber[7];
|
||
|
||
// Пришло врема!
|
||
/* Записывает DAC_go значением 6; начальный ток нагрузки в мА, технологический регистр 0x50. */
|
||
DAC_go = 6; // начало зарада
|
||
LOAD_CAN_TIMEOUT = 2000; /* ms without fresh ZPT: freeze ramp. */ /* Записывает LOAD_CAN_TIMEOUT значением 2000; сохраняемый тайм-аут свежести напряжения CAN в миллисекундах, регистр 0x52. */
|
||
/* Устанавливает прежний заводской лимит пяти пусков, включая первый START; настройка хранится в сохраняемом регистре 0x7D. */
|
||
LOAD_MAX_ATTEMPTS = LOAD_DEFAULT_MAX_ATTEMPTS;
|
||
/* Записывает DAC_stop значением 16; конечный ток нагрузки в мА, технологический регистр 0x51. */
|
||
DAC_stop= 16; // конец зарада
|
||
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Проверяет if(Kurrent); последующий оператор выполняется только при истинном условии. */
|
||
if(Kurrent)
|
||
/* Цикл for(i=0;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<4;i++)
|
||
/* Записывает Zero_lev[i] значением 0x800; данные Zero_lev. */
|
||
Zero_lev[i] = 0x800;
|
||
|
||
/* Инициализирует модуль вызовом Init_sensors_more(); перед его дальнейшим использованием. */
|
||
Init_sensors_more();
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Читает сохранённые регистры из области параметров EEPROM и применяет настройки платы. */
|
||
void Load_params()
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет i — данные i; crc — данные crc. */
|
||
unsigned int i,crc;
|
||
|
||
/* Вызывает Seeprom_read. Читает EEPROM порциями; адрес задаётся словами C28x, размер переводится в число передаваемых слов. */
|
||
Seeprom_read(BALSAM167_EEPROM_PARAMS_START_WORD, param, (ANSWER_LEN+1)*2);
|
||
/* Записывает crc значением get_crc16(param,ANSWER_LEN); данные crc. */
|
||
crc = get_crc16(param,ANSWER_LEN);
|
||
/* Проверяет if( (crc==param[ANSWER_LEN]) и; последующий оператор выполняется только при истинном условии. */
|
||
if( (crc==param[ANSWER_LEN]) &&
|
||
/* Продолжает список аргументов, полей или выражение (crc !=0xFFFF) &&; порядок элементов сохраняется. */
|
||
(crc !=0xFFFF) &&
|
||
/* Продолжает список аргументов, полей или выражение (Mode == param[126]) ); порядок элементов сохраняется. */
|
||
(Mode == param[126]) )
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Цикл for(i=0;i<ANSWER_LEN;i++) modbus[i] = param[i];; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<ANSWER_LEN;i++) modbus[i] = param[i];
|
||
/* Записывает Commands значением 0; слово команд, технологический регистр 127. */
|
||
Commands=0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||
else
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Восстанавливает заводские параметры после неверного CRC или несоответствия режима платы; LOAD_CAN_TIMEOUT получает 2000 мс. */
|
||
Default_params();
|
||
/* Записывает Commands значением 0; слово команд, технологический регистр 127. */
|
||
Commands=0;
|
||
/* Вызывает Save_params. Сохраняет технологические регистры в область параметров, отделённую от загрузочного образа EEPROM. */
|
||
Save_params();
|
||
/* Проверяет if(TermoSW); последующий оператор выполняется только при истинном условии. */
|
||
if(TermoSW)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает cTermoCal значением 1; данные cTermoCal. */
|
||
cTermoCal =1;
|
||
/* Записывает Caliber_time значением 0xFFFF; данные Caliber_time. */
|
||
Caliber_time = 0xFFFF;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
} } }
|
||
|
||
/* Сохраняет технологические регистры в область параметров, отделённую от загрузочного образа EEPROM. */
|
||
void Save_params()
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет i — данные i; dif — данные dif. Начальное значение задаётся справа от знака равенства. */
|
||
unsigned int i,dif=0;
|
||
|
||
/* Цикл for(i=0;i<ANSWER_LEN;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for(i=0;i<ANSWER_LEN;i++)
|
||
/* Проверяет if(param[i] != modbus[i]); последующий оператор выполняется только при истинном условии. */
|
||
if(param[i] != modbus[i])
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает param[i] значением modbus[i]; данные param. */
|
||
param[i] = modbus[i];
|
||
/* Записывает dif значением 1; данные dif. */
|
||
dif=1;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Проверяет if(dif); последующий оператор выполняется только при истинном условии. */
|
||
if(dif)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает param[ANSWER_LEN] значением get_crc16(param,ANSWER_LEN); данные param. */
|
||
param[ANSWER_LEN] = get_crc16(param,ANSWER_LEN);
|
||
/* Вызывает Seeprom_write. Пишет EEPROM с разделением по физическим страницам; область параметров не пересекает образ прошивки. */
|
||
Seeprom_write(BALSAM167_EEPROM_PARAMS_START_WORD,param,(ANSWER_LEN+1)*2);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
} }
|
||
|
||
/***************************************************************/
|
||
/***************************************************************/
|
||
/* Передача данных по протоколу ModBus - команда 3
|
||
Чтение ачеек данных */
|
||
/***************************************************************/
|
||
/***************************************************************/
|
||
|
||
/* Формирует ответ Modbus с установленным старшим битом функции и кодом исключения. */
|
||
static void modbus_exception(RS_DATA *rs_arr, unsigned int function, unsigned int error)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет crc — данные crc. */
|
||
unsigned int crc;
|
||
/* Записывает rs_arr->buffer[0] значением CNTRL_ADDR; rs arr буфер. */
|
||
rs_arr->buffer[0] = CNTRL_ADDR;
|
||
/* Записывает rs_arr->buffer[1] значением function | 0x80; rs arr буфер. */
|
||
rs_arr->buffer[1] = function | 0x80;
|
||
/* Записывает rs_arr->buffer[2] значением error; rs arr буфер. */
|
||
rs_arr->buffer[2] = error;
|
||
/* Записывает crc значением get_crc_16(0xFFFF, rs_arr->buffer, 3); данные crc. */
|
||
crc = get_crc_16(0xFFFF, rs_arr->buffer, 3);
|
||
/* Записывает rs_arr->buffer[3] значением LOBYTE(crc); rs_arr->buffer[4] = HIBYTE(crc); rs arr буфер. */
|
||
rs_arr->buffer[3] = LOBYTE(crc); rs_arr->buffer[4] = HIBYTE(crc);
|
||
/* Записывает rs_arr->flag_TIMEOUT_to_Send значением true; rs arr флаг TIMEOUT to Send. */
|
||
rs_arr->flag_TIMEOUT_to_Send = true;
|
||
/* Вызывает RS_Send. Передаёт массив слов через SCI в выбранном режиме упаковки. */
|
||
RS_Send(rs_arr, rs_arr->buffer, 5);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* UART parser has already validated CRC and accepted the device address. */
|
||
/* Маршрутизирует расширенные адреса: RAM УМП/GAS захватывается под краткой блокировкой IRQ, а чтение EEPROM выполняется с разрешёнными IRQ, поскольку SPI продвигается из Timer2. */
|
||
static int receive_ump(RS_DATA *rs_arr)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет address — адрес; value — данные value; saved — данные saved; length — длина; count — число. */
|
||
unsigned int address, value, saved, length, count, error;
|
||
/* Main-loop only; encoded into the UART buffer before the next request.
|
||
* Keep the 124-word snapshot off the shared interrupt stack. */
|
||
/* Статический буфер хранит до 124 слов снимка вне общего стека прерываний; главный цикл сериализует его до обработки следующего запроса. */
|
||
static uint16_t words[UMP_MAX_WORDS];
|
||
/* Записывает address значением (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; адрес. */
|
||
address = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||
/* Проверяет if (address < UMP_BASE) return 0; последующий оператор выполняется только при истинном условии. */
|
||
if (address < UMP_BASE) return 0;
|
||
/* Записывает value значением (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; данные value. */
|
||
value = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||
/* SPI driver advances in Timer2 ISR: NEVER mask interrupts here.
|
||
* Reuse the existing snapshot buffer; the main loop owns this transaction.
|
||
* The shared validator rejects writes, wraparound and out-of-device reads. */
|
||
/* Проверяет if (address >= 0x1300U и address < 0x1308U); последующий оператор выполняется только при истинном условии. */
|
||
if (address >= 0x1300U && address < 0x1308U) {
|
||
/* Записывает count значением Load_protection_prepare(rs_arr->RS_Header[1], address, value, words, &error); число. */
|
||
count = Load_protection_prepare(rs_arr->RS_Header[1], address, value, words, &error);
|
||
/* Проверяет else if (address >= BALSAM167_EEPROM_RTU_BASE); последующий оператор выполняется только при истинном условии. */
|
||
} else if (address >= BALSAM167_EEPROM_RTU_BASE) {
|
||
/* Записывает error значением 2; ошибка. */
|
||
error = 2;
|
||
/* Условие компиляции EEPROM_M95M02: выбранный блок включается в текущий вариант прошивки. */
|
||
#if EEPROM_M95M02
|
||
/* Exception 3 prevents old AT-profile clients from falling back to
|
||
* legacy PEEK after a profile mismatch. No SPI transaction is issued. */
|
||
/* Проверяет if (!(value & BALSAM167_EEPROM_M95_MARKER)) error = 3; последующий оператор выполняется только при истинном условии. */
|
||
if (!(value & BALSAM167_EEPROM_M95_MARKER)) error = 3;
|
||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||
#endif
|
||
/* Записывает count значением 0; число. */
|
||
count = 0;
|
||
/* Проверяет if (balsam167_eeprom_block_valid(rs_arr->RS_Header[1], address, value)); последующий оператор выполняется только при истинном условии. */
|
||
if (balsam167_eeprom_block_valid(rs_arr->RS_Header[1], address, value)) {
|
||
/* Условие компиляции EEPROM_M95M02: выбранный блок включается в текущий вариант прошивки. */
|
||
#if EEPROM_M95M02
|
||
/* Записывает count значением value & 255U; число. */
|
||
count = value & 255U;
|
||
/* Вызывает Seeprom_read. Читает EEPROM порциями; адрес задаётся словами C28x, размер переводится в число передаваемых слов. */
|
||
Seeprom_read(balsam167_eeprom_block_word(address, value), words, count * 2);
|
||
/* Выбирает альтернативный блок текущего условия компиляции. */
|
||
#else
|
||
/* Записывает count значением value; число. */
|
||
count = value;
|
||
/* Вызывает Seeprom_read. Читает EEPROM порциями; адрес задаётся словами C28x, размер переводится в число передаваемых слов. */
|
||
Seeprom_read(address - BALSAM167_EEPROM_RTU_BASE, words, count * 2);
|
||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||
#endif
|
||
/* Записывает error значением 0; ошибка. */
|
||
error = 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||
} else {
|
||
/* Записывает saved значением __disable_interrupts(); данные saved. */
|
||
saved = __disable_interrupts();
|
||
/* Условие компиляции EEPROM_M95M02: выбранный блок включается в текущий вариант прошивки. */
|
||
#if EEPROM_M95M02
|
||
/* Проверяет if (gas167_contains(address)); последующий оператор выполняется только при истинном условии. */
|
||
if (gas167_contains(address))
|
||
/* Записывает count значением gas167_prepare(rs_arr->RS_Header[1], address, value, 0, words, &error); число. */
|
||
count = gas167_prepare(rs_arr->RS_Header[1], address, value, 0, words, &error);
|
||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||
else
|
||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||
#endif
|
||
/* Записывает count значением ump_tms28335_capture(rs_arr->RS_Header[1], address, value, words, &error); число. */
|
||
count = ump_tms28335_capture(rs_arr->RS_Header[1], address, value, words, &error);
|
||
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
|
||
__restore_interrupts(saved);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Записывает length значением ump_rtu_encode(CNTRL_ADDR, rs_arr->RS_Header[1], error,; длина. */
|
||
length = ump_rtu_encode(CNTRL_ADDR, rs_arr->RS_Header[1], error,
|
||
/* Продолжает список аргументов, полей или выражение words, count, rs_arr->buffer, MAX_SEND_LENGTH);; порядок элементов сохраняется. */
|
||
words, count, rs_arr->buffer, MAX_SEND_LENGTH);
|
||
/* Проверяет if (length); последующий оператор выполняется только при истинном условии. */
|
||
if (length) {
|
||
/* Записывает rs_arr->flag_TIMEOUT_to_Send значением true; rs arr флаг TIMEOUT to Send. */
|
||
rs_arr->flag_TIMEOUT_to_Send = true;
|
||
/* Вызывает RS_Send. Передаёт массив слов через SCI в выбранном режиме упаковки. */
|
||
RS_Send(rs_arr, rs_arr->buffer, length);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Завершает receive_ump и возвращает 1. */
|
||
return 1;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Обслуживает чтение регистров FC03 с проверкой адреса, длины и формированием ответа RTU. */
|
||
void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет crc — данные crc; Address_MB — адрес MB; Length_MB — длина MB; i — данные i; value — данные value. */
|
||
unsigned int crc, Address_MB, Length_MB, i, value;
|
||
/* Проверяет if (receive_ump(rs_arr)) return; последующий оператор выполняется только при истинном условии. */
|
||
if (receive_ump(rs_arr)) return;
|
||
|
||
// получили начальный адрес чтениа
|
||
/* Записывает Address_MB значением (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; адрес MB. */
|
||
Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||
|
||
// получили количество слов данных
|
||
/* Записывает Length_MB значением (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; длина MB. */
|
||
Length_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||
/* Проверяет if (!Length_MB или Length_MB > 125 или; последующий оператор выполняется только при истинном условии. */
|
||
if (!Length_MB || Length_MB > 125 ||
|
||
/* Продолжает список аргументов, полей или выражение !(Address_MB < ANSWER_LEN && Length_MB <= ANSWER_LEN-Address_MB)) {; порядок элементов сохраняется. */
|
||
!(Address_MB < ANSWER_LEN && Length_MB <= ANSWER_LEN-Address_MB)) {
|
||
/* Вызывает modbus_exception. Формирует ответ Modbus с установленным старшим битом функции и кодом исключения. */
|
||
modbus_exception(rs_arr, CMD_MODBUS_3, 2); return;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/////////////////////////////////////////////////
|
||
// Отсылка
|
||
/* Посчитали контрольную сумму перед самой посылкой */
|
||
|
||
/* Записывает rs_arr->buffer[0] значением CNTRL_ADDR; rs arr буфер. */
|
||
rs_arr->buffer[0] = CNTRL_ADDR;
|
||
/* Записывает rs_arr->buffer[1] значением CMD_MODBUS_3; rs arr буфер. */
|
||
rs_arr->buffer[1] = CMD_MODBUS_3;
|
||
/* Записывает rs_arr->buffer[2] значением Length_MB*2; rs arr буфер. */
|
||
rs_arr->buffer[2] = Length_MB*2;
|
||
|
||
/* Штатные регистры копируются последовательно без блокировки IRQ вокруг всего блока.
|
||
* Измерительные ISR могут обновить соседние слова между чтениями; этот путь не гарантирует
|
||
* единый момент захвата всех значений. RAM-расширения захватываются отдельно в receive_ump. */
|
||
/* Формирует payload из запрошенного числа 16-битных слов; для каждого слова в ответе нужны два байта. */
|
||
for (i=0;i<Length_MB;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Читает очередное слово один раз, чтобы старший и младший байты ответа относились к одному считанному значению. */
|
||
value = modbus[Address_MB+i];
|
||
/* Помещает старший байт слова после трёхбайтного заголовка; данные регистра передаются старшим байтом вперёд. */
|
||
rs_arr->buffer[3+i*2] = (value >> 8) & 0xFF;
|
||
/* Помещает младший байт непосредственно за старшим, сохраняя исходный 16-битный рисунок регистра. */
|
||
rs_arr->buffer[3+i*2+1] = value & 0xFF;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Записывает crc значением 0xffff; данные crc. */
|
||
crc = 0xffff;
|
||
/* Записывает crc значением get_crc_16(crc, rs_arr->buffer, Length_MB*2+3); данные crc. */
|
||
crc = get_crc_16(crc, rs_arr->buffer, Length_MB*2+3);
|
||
|
||
/* Записывает rs_arr->buffer[Length_MB*2+3] значением LOBYTE(crc); rs arr буфер. */
|
||
rs_arr->buffer[Length_MB*2+3] = LOBYTE(crc);
|
||
/* Записывает rs_arr->buffer[Length_MB*2+4] значением HIBYTE(crc); rs arr буфер. */
|
||
rs_arr->buffer[Length_MB*2+4] = HIBYTE(crc);
|
||
|
||
/* Первый исторический нулевой байт после CRC; входит в увеличенную длину штатного ответа. */
|
||
rs_arr->buffer[Length_MB*2+5] = 0;
|
||
/* Второй исторический нулевой байт после CRC; сохраняет прежний формат низких технологических адресов. */
|
||
rs_arr->buffer[Length_MB*2+6] = 0;
|
||
/* Третий исторический нулевой байт после CRC; это последний элемент передаваемого буфера при длине 2*N+8. */
|
||
rs_arr->buffer[Length_MB*2+7] = 0;
|
||
/* Дополнительный ноль находится за длиной, переданной в RS_Send; в текущий ответ это слово не отправляется. */
|
||
rs_arr->buffer[Length_MB*2+8] = 0;
|
||
|
||
/* Записывает rs_arr->flag_TIMEOUT_to_Send значением true; rs arr флаг TIMEOUT to Send. */
|
||
rs_arr->flag_TIMEOUT_to_Send=true;
|
||
/* Расширение логгера отвечает точным кадром Modbus без хвостовых
|
||
* нулей: они иначе попали бы в начало ответа следующего блока GUI.
|
||
* Исторический формат технологических регистров оставлен прежним. */
|
||
/* Вызывает RS_Send. Передаёт массив слов через SCI в выбранном режиме упаковки. */
|
||
RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+8);
|
||
|
||
/* Завершает ReceiveCommandModbus3 без возвращаемого значения. */
|
||
return;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Обслуживает одиночную запись FC06, проверяя доступность регистра и допустимость значения. */
|
||
void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет Address_MB — адрес MB; Data_MB — данные MB; i — данные i. */
|
||
unsigned int Address_MB, Data_MB, i;
|
||
/* Проверяет if (receive_ump(rs_arr)) return; последующий оператор выполняется только при истинном условии. */
|
||
if (receive_ump(rs_arr)) return;
|
||
|
||
/////////////////////////////////////////////////
|
||
// Отсылка
|
||
/* Отправлаем назад то же самое */
|
||
|
||
/* Цикл for (i=0;i<8;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for (i=0;i<8;i++)
|
||
/* Записывает rs_arr->buffer[i] значением rs_arr->RS_Header[i]; rs arr буфер. */
|
||
rs_arr->buffer[i] = rs_arr->RS_Header[i];
|
||
|
||
|
||
// получили начальный адрес записи
|
||
/* Записывает Address_MB значением (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; адрес MB. */
|
||
Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||
|
||
// получили слово данных
|
||
/* Записывает Data_MB значением (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; данные MB. */
|
||
Data_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||
|
||
/* На плате LOAD запрещает запись только состояния защиты 0x7C; регистр лимита 0x7D принимает настройку. */
|
||
if (Desk == dsk_LOAD && Address_MB == 0x7CU) {
|
||
/* Вызывает modbus_exception. Формирует ответ Modbus с установленным старшим битом функции и кодом исключения. */
|
||
modbus_exception(rs_arr, CMD_MODBUS_6, 2); return;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Ноль в лимите 0x7D недопустим: первый пуск должен входить в разрешённые 1..65535 попыток. */
|
||
if (Desk == dsk_LOAD && Address_MB == 0x7DU && Data_MB == 0U) {
|
||
/* Возвращает код Modbus 3 для недопустимого значения, сохраняя прежний лимит и состояние автомата. */
|
||
modbus_exception(rs_arr, CMD_MODBUS_6, 3); return;
|
||
/* Завершает проверку ненулевого лимита перед общей записью технологического слова. */
|
||
}
|
||
/* Проверяет if (Desk == dsk_LOAD и Address_MB == 0x52U и; последующий оператор выполняется только при истинном условии. */
|
||
if (Desk == dsk_LOAD && Address_MB == 0x52U &&
|
||
/* Продолжает список аргументов, полей или выражение (Data_MB == 0U || Data_MB > 60000U)) {; порядок элементов сохраняется. */
|
||
(Data_MB == 0U || Data_MB > 60000U)) {
|
||
/* Вызывает modbus_exception. Формирует ответ Modbus с установленным старшим битом функции и кодом исключения. */
|
||
modbus_exception(rs_arr, CMD_MODBUS_6, 3); return;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
/* Проверяет if (Address_MB < ANSWER_LEN); последующий оператор выполняется только при истинном условии. */
|
||
if (Address_MB < ANSWER_LEN) {
|
||
/* Записывает Modbus[Address_MB].all значением Data_MB; представление регистра целым словом без разбиения на битовые поля. */
|
||
Modbus[Address_MB].all = Data_MB;
|
||
/* Проверяет if (Address_MB == 127) ump_log_rs(); последующий оператор выполняется только при истинном условии. */
|
||
if (Address_MB == 127) ump_log_rs();
|
||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||
} else { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; }
|
||
|
||
/* Записывает rs_arr->flag_TIMEOUT_to_Send значением true; rs arr флаг TIMEOUT to Send. */
|
||
rs_arr->flag_TIMEOUT_to_Send=true;
|
||
/* Вызывает RS_Send. Передаёт массив слов через SCI в выбранном режиме упаковки. */
|
||
RS_Send(rs_arr, rs_arr->buffer, 10);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Начинает функцию SendCommandModbus4; назначение модуля — обработка Modbus, заводские параметры и сохранение настроек. */
|
||
void SendCommandModbus4(RS_DATA *rs_arr)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет crc — данные crc. */
|
||
unsigned int crc;
|
||
|
||
/////////////////////////////////////////////////
|
||
// Отсылка
|
||
|
||
/* Записывает rs_arr->buffer[0] значением 16; rs arr буфер. */
|
||
rs_arr->buffer[0] = 16;
|
||
/* Записывает rs_arr->buffer[1] значением 4; rs arr буфер. */
|
||
rs_arr->buffer[1] = 4;
|
||
/* Записывает rs_arr->buffer[2] значением 0; rs arr буфер. */
|
||
rs_arr->buffer[2] = 0;
|
||
/* Записывает rs_arr->buffer[3] значением 0; rs arr буфер. */
|
||
rs_arr->buffer[3] = 0;
|
||
/* Записывает rs_arr->buffer[4] значением 0; rs arr буфер. */
|
||
rs_arr->buffer[4] = 0;
|
||
/* Записывает rs_arr->buffer[5] значением 48; rs arr буфер. */
|
||
rs_arr->buffer[5] = 48;
|
||
|
||
/* Записывает crc значением 0xffff; данные crc. */
|
||
crc = 0xffff;
|
||
/* Записывает crc значением get_crc_16(crc, rs_arr->buffer, 6); данные crc. */
|
||
crc = get_crc_16(crc, rs_arr->buffer, 6);
|
||
|
||
/* Записывает rs_arr->buffer[6] значением LOBYTE(crc); rs arr буфер. */
|
||
rs_arr->buffer[6] = LOBYTE(crc);
|
||
/* Записывает rs_arr->buffer[7] значением HIBYTE(crc); rs arr буфер. */
|
||
rs_arr->buffer[7] = HIBYTE(crc);
|
||
|
||
//rs_arr->buffer[8] = 0;
|
||
//rs_arr->buffer[9] = 0;
|
||
//rs_arr->buffer[10] = 0;
|
||
|
||
/* Записывает rs_arr->flag_TIMEOUT_to_Send значением true; rs arr флаг TIMEOUT to Send. */
|
||
rs_arr->flag_TIMEOUT_to_Send=true;
|
||
/* Вызывает RS_Send. Передаёт массив слов через SCI в выбранном режиме упаковки. */
|
||
RS_Send(rs_arr, rs_arr->buffer, 8);
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|
||
|
||
/* Начинает функцию ReceiveAnswerModbus4; назначение модуля — обработка Modbus, заводские параметры и сохранение настроек. */
|
||
void ReceiveAnswerModbus4(RS_DATA *rs_arr)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Объявляет i — данные i. */
|
||
unsigned int i;
|
||
|
||
/////////////////////////////////////////////////
|
||
// Отсылка
|
||
|
||
/* Цикл for (i=0;i<8;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||
for (i=0;i<8;i++)
|
||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||
{
|
||
/* Записывает ext_temp[i] значением ( rs_arr->RS_Header[5+i*12] << 8) +; данные ext_temp. */
|
||
ext_temp[i] = ( rs_arr->RS_Header[5+i*12] << 8) +
|
||
/* Продолжает список аргументов, полей или выражение rs_arr->RS_Header[6+i*12];; порядок элементов сохраняется. */
|
||
rs_arr->RS_Header[6+i*12];
|
||
|
||
/* Записывает ext_diag[i] значением ( rs_arr->RS_Header[7+i*12] |; данные ext_diag. */
|
||
ext_diag[i] = ( rs_arr->RS_Header[7+i*12] |
|
||
/* Продолжает список аргументов, полей или выражение rs_arr->RS_Header[8+i*12] ) != 0;; порядок элементов сохраняется. */
|
||
rs_arr->RS_Header[8+i*12] ) != 0;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
} }
|
||
|
||
|