Files
Balsam_167/Source/Internal/message.c
T
Andrey 31f92e89d9 Обновить сборку прошивки 166, TESTLAMP и кодировку исходников
Перенести настройки выпуска в JSON, добавить переносимый сценарий сборки и проверки BIN. Обновить конфигурации CCS, исходники в UTF-8, обработку TESTLAMP, образы прошивки и регрессионные проверки.
2026-10-17 14:36:59 +03:00

331 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Параметры и обработчики Modbus после проверки CRC. Массив modbus
* содержит обычные адреса 0..127, область 0x1000 обслуживает логгер.
* EEPROM хранит параметры, но не является источником START/STOP:
* при загрузке сохраняется последняя живая команда нагрузки.
* Функции вызываются из main; EEPROM блокирует этот контекст.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "package.h"
#include "RS485.h"
#include "crc16.h"
#include "cntrl_adr.h"
#include "bios_dsp.h"
#include "message.h"
#include "filter_bat2.h"
#include "measure.h"
#include "ADC.h"
#include "peripher.h"
#include "ecan.h"
#include "pulto.h"
#include "spise2p.h"
#include "include/balsam167_eeprom_block.h" /* Использует общий с 167 контракт FC03: окно 0x8000..0xBFFF, до 120 слов AT25256B за запрос. */
#include "caliber.h"
#include "log_to_mem.h"
#include "firmware_info.h" /* Подключает адрес и границы неизменяемого паспорта 0x1200, совместимого с проверкой прошивки в 167. */
#include "../src/firmware_info_static.c" /* Собирает общие 12 слов firmware-info через include-путь firmware-info/include; как в 167, копии упаковщика в проекте нет. */
#include "DAC.h"
int modbus[ANSWER_LEN+1];
unsigned int param[ANSWER_LEN+1];
void Default_params()
{
unsigned int i,def;
int shkf_lo_edge[] = {300, // 380
300, // 38O
0, // 0
0, // 0
15, // 31
22, // 27
20, // 24
10, // 15
60}; // AD
int bright[] = {10,8,6,8,6,8};
for(i=0;i<ANSWER_LEN;i++)
{
/* Команда нагрузки не является параметром по умолчанию. */
if (Desk != dsk_LOAD || i != 127) Modbus[i].all = 0;
}
UMP_reset_parameter_commands();
LastMode = Mode;
if(Desk == dsk_EPLT)
{
Cancount[m_FAST] = 10; // Задаёт для пульта быстрый CAN-пакет раз в 10 базовых интервалов CANPOWSE по 20 мс, то есть примерно 200 мс; это значение по умолчанию, которое могут заменить параметры EEPROM.
for(i=0;i<6;i++) Bright[i] = bright[i];
}
else
{
Cancount[m_FAST] = 12; // пауза между посылками CAN
Brightness = 8;
}
Cancount[m_SLOW] = 50; // Задаёт медленную CAN-рассылку раз в 50 базовых интервалов CANPOWSE по 20 мс, то есть примерно раз в секунду; это значение по умолчанию могут заменить параметры EEPROM.
if(Kalibro)
{
def = Mode-3;
if(Mode==adr_SHKF) def=4;
for(i=0;i<8;i++) Caliber[i] = def_cal[def][i];
}
if(Desk == dsk_COMM)
{
for(i=0;i<TPL_POW*2;i++)
{
sens_hi_edge[i] = 70;
sens_lo_edge[i] = 60;
} }
if(Desk==dsk_BKSD)
{
for(i=0;i<6;i++)
{
sens_hi_edge[i] = 170;
sens_lo_edge[i] = 150;
}
for(i=6;i<8;i++)
{
sens_hi_edge[i] = 115;
sens_lo_edge[i] = 105;
} }
if(Desk==dsk_BKST)
for(i=0;i<TPL_TRN*2;i++)
{
sens_hi_edge[i] = 70;
sens_lo_edge[i] = 60;
}
if(Mode==adr_SHKF)
{
for(i=0;i<15;i++) sens_lo_edge[i] = shkf_lo_edge[sens_type[i]];
sens_hi_edge[13] = 70;
sens_hi_edge[14] = 70;
}
if(Desk==dsk_LOAD)
{
sens_hi_edge[0] = 420;
sens_hi_edge[1] = 420;
sens_hi_edge[2] = 900;
sens_hi_edge[3] = 900;
sens_lo_edge[0] = 300;
sens_lo_edge[1] = 300;
sens_lo_edge[2] = 800;
sens_lo_edge[3] = 800;
DAC_20 = Caliber[6];
DAC_04 = Caliber[7];
/* Не врема!
DAC_go = 6; // начало зарада
DAC_stop= 15; // конец зарада
*/
}
if(Kurrent)
for(i=0;i<4;i++)
Zero_lev[i] = 0x800;
Init_sensors_more();
}
/* CRC и Mode проверяются до применения EEPROM. Слово 127
* нагрузки не копируется даже временно: ISR не должен увидеть
* старый START из EEPROM либо потерять текущую CAN-команду.
*/
void Load_params()
{
unsigned int i,crc;
Seeprom_read(0x3FFF-(ANSWER_LEN+1), param, (ANSWER_LEN+1)*2);
crc = get_crc16(param,ANSWER_LEN);
if( (crc==param[ANSWER_LEN]) &&
(crc !=0xFFFF) &&
(Mode == param[126]))
{
/* Не восстанавливать START/STOP из EEPROM даже на один тик ISR. */
for(i=0;i<ANSWER_LEN;i++)
if (Desk != dsk_LOAD || i != 127) modbus[i] = param[i];
UMP_reset_parameter_commands();
}
else
{
Default_params();
UMP_reset_parameter_commands();
Save_params();
if(Desk == dsk_COMM)
{
cTermoCal = 1;
Caliber_time = 0xFFFF;
} } }
/* ISR продолжает менять измерения во время сбора param. CRC
* относится к собранному массиву, а не атомарному снимку всей платы.
* Не вызывать сохранение из критического пути дискретов.
*/
void Save_params()
{
unsigned int i,dif=0;
for(i=0;i<ANSWER_LEN;i++)
if(param[i] != modbus[i])
{
param[i] = modbus[i];
dif=1;
}
if(dif)
{
param[ANSWER_LEN] = get_crc16(param,ANSWER_LEN);
Seeprom_write(0x3FFF-(ANSWER_LEN+1),param,(ANSWER_LEN+1)*2);
} }
/***************************************************************/
/***************************************************************/
/* Передача данных по протоколу ModBus - команда 3
Чтение ачеек данных */
/***************************************************************/
/***************************************************************/
static void modbus_exception(RS_DATA *rs_arr, unsigned int function, unsigned int error)
{
unsigned int crc;
rs_arr->buffer[0] = CNTRL_ADDR;
rs_arr->buffer[1] = function | 0x80;
rs_arr->buffer[2] = error;
crc = get_crc_16(0xFFFF, rs_arr->buffer, 3);
rs_arr->buffer[3] = LOBYTE(crc); rs_arr->buffer[4] = HIBYTE(crc);
rs_arr->flag_TIMEOUT_to_Send = true;
RS_Send(rs_arr, rs_arr->buffer, 5);
}
void ReceiveCommandModbus3(RS_DATA *rs_arr)
{
unsigned int crc, Address_MB, Length_MB, i, value, saved = 0;
// получили начальный адрес чтениа
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];
if (Address_MB >= BALSAM167_EEPROM_RTU_BASE) { /* Выделяет только верхнее окно EEPROM; старые регистры, логгер и паспорт обрабатываются прежним кодом ниже. */
if (!balsam167_eeprom_block_valid_profile(CMD_MODBUS_3, Address_MB, Length_MB, 0U)) { /* Профиль 0 сохраняет контракт 167 для 32 КиБ: запрещает пустой блок, более 120 слов, M95 и выход за конец окна. */
modbus_exception(rs_arr, CMD_MODBUS_3, 2U); /* Возвращает Illegal Data Address с CRC до любого обращения к SPI при неверном диапазоне. */
return; /* Не допускает перехода ошибочного запроса EEPROM к backend логгера или обычным регистрам. */
} /* Валидатор проверяет конец через вычитание, поэтому переполнение 16-битного адреса не разрешает чтение. */
Seeprom_read(Address_MB - BALSAM167_EEPROM_RTU_BASE, &rs_arr->buffer[3], Length_MB * 2U); /* Как в 167, SPI получает адрес в 16-битных словах и длину в октетах; IRQ остаются разрешены для автомата Timer2. */
for (i = Length_MB; i > 0U; --i) { /* Разворачивает прочитанные слова с конца в том же UART-буфере без нового массива и перезаписи ещё не обработанных слов. */
value = rs_arr->buffer[i + 2U]; /* Временное слово сохраняет оба SPI-октета до расширения одного элемента C28x в два октета RTU. */
rs_arr->buffer[i * 2U + 2U] = value & 0xFFU; /* Записывает младший октет слова после старшего, как требует физический дамп EEPROM в SETGUI. */
rs_arr->buffer[i * 2U + 1U] = (value >> 8) & 0xFFU; /* Маска 0xFF выделяет восемь бит линии из 16-битного unsigned int C28x. */
} /* Обратный обход корректен и для одного слова, и для максимального блока из 120 слов. */
rs_arr->buffer[0] = CNTRL_ADDR; /* Отвечает собственным адресом платы, сохраняя поддержку общего адреса 16 существующим приёмником. */
rs_arr->buffer[1] = CMD_MODBUS_3; /* Возвращает стандартную команду FC03 без введения отдельной команды BIOS или записи памяти. */
rs_arr->buffer[2] = Length_MB * 2U; /* Число полезных октетов находится в диапазоне 2..240 и помещается в одном октете RTU. */
crc = get_crc_16(0xFFFFU, rs_arr->buffer, Length_MB * 2U + 3U); /* Проверяет адрес, команду, длину и весь блок тем же Modbus CRC16, что остальные ответы прошивки. */
rs_arr->buffer[Length_MB * 2U + 3U] = LOBYTE(crc); /* Передаёт младший октет CRC первым в соответствии с Modbus RTU. */
rs_arr->buffer[Length_MB * 2U + 4U] = HIBYTE(crc); /* Завершает кадр старшим октетом CRC без устаревшего нулевого хвоста. */
rs_arr->flag_TIMEOUT_to_Send = true; /* Использует штатное управление таймаутом UART при отправке готового ответа из main. */
RS_Send(rs_arr, rs_arr->buffer, Length_MB * 2U + 5U); /* Отправляет ровно 5 служебных октетов плюс данные, максимум 245 элементов из существующего буфера на 400. */
return; /* Завершает только новый маршрут EEPROM, сохраняя прежние форматы остальных ответов FC03. */
} /* Новый маршрут не меняет PEEK, запись EEPROM, адреса параметров или драйвер SPI. */
if (!Length_MB || Length_MB > 125 ||
!((Address_MB < ANSWER_LEN && Length_MB <= ANSWER_LEN-Address_MB) ||
(Address_MB >= UMP_LOG_BASE && Address_MB <= UMP_LOG_BASE+15 &&
Length_MB <= UMP_LOG_BASE+16-Address_MB) ||
(Address_MB >= UMP_LOG_DATA && Address_MB < UMP_LOG_DATA+120 &&
Length_MB <= UMP_LOG_DATA+120-Address_MB) ||
(Address_MB == UMP_LOG_LIVE && Length_MB == 124) || /* Сохраняет точное прежнее 124-словное онлайн-окно логгера. */
firmware_info_range(Address_MB, Length_MB))) { /* Дополнительно разрешает только полное или частичное чтение двенадцати регистров паспорта. */
modbus_exception(rs_arr, CMD_MODBUS_3, 2); return;
}
/////////////////////////////////////////////////
// Отсылка
/* Посчитали контрольную сумму перед самой посылкой */
rs_arr->buffer[0] = CNTRL_ADDR;
rs_arr->buffer[1] = CMD_MODBUS_3;
rs_arr->buffer[2] = Length_MB*2;
/* Защищаем целостность одного снимка/блока; передача UART идёт уже
* с разрешёнными прерываниями и не задерживает измерение/управление. */
if (Address_MB >= UMP_LOG_BASE && Address_MB < FIRMWARE_INFO_ADDRESS) saved = __disable_interrupts(); /* Неизменяемый паспорт не требует блокировки IRQ; целостность прежних снимков логгера сохраняется. */
for (i=0;i<Length_MB;i++)
{
if (Address_MB >= FIRMWARE_INFO_ADDRESS) value = firmware_info_static_read(Address_MB - FIRMWARE_INFO_ADDRESS + i); /* После проверки диапазона читает только соответствующее слово статического паспорта, без обращения к логгеру. */
else value = Address_MB >= UMP_LOG_BASE ? ump_log_read(Address_MB+i) : (unsigned int)modbus[Address_MB+i]; /* Сохраняет прежнюю маршрутизацию и беззнаковое представление 16-битных слов технологической карты и логгера v4. */
rs_arr->buffer[3+i*2] = (value >> 8) & 0xFF;
rs_arr->buffer[3+i*2+1] = value & 0xFF;
}
if (Address_MB >= UMP_LOG_BASE && Address_MB < FIRMWARE_INFO_ADDRESS) __restore_interrupts(saved); /* Возвращает сохранённую маску только для действительно защищённого снимка логгера. */
crc = 0xffff;
crc = get_crc_16(crc, rs_arr->buffer, Length_MB*2+3);
rs_arr->buffer[Length_MB*2+3] = LOBYTE(crc);
rs_arr->buffer[Length_MB*2+4] = HIBYTE(crc);
rs_arr->buffer[Length_MB*2+5] = 0;
rs_arr->buffer[Length_MB*2+6] = 0;
rs_arr->buffer[Length_MB*2+7] = 0;
rs_arr->buffer[Length_MB*2+8] = 0;
rs_arr->flag_TIMEOUT_to_Send=true;
/* Расширение логгера отвечает точным кадром Modbus без хвостовых
* нулей: они иначе попали бы в начало ответа следующего блока GUI.
* Исторический формат технологических регистров оставлен прежним. */
RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+(Address_MB >= UMP_LOG_BASE ? 5 : 8));
return;
}
void ReceiveCommandModbus6(RS_DATA *rs_arr)
{
unsigned int Address_MB, Data_MB, i;
/////////////////////////////////////////////////
// Отсылка
/* Отправлаем назад то же самое */
for (i=0;i<8;i++)
rs_arr->buffer[i] = rs_arr->RS_Header[i];
// получили начальный адрес записи
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];
if (Address_MB >= FIRMWARE_INFO_ADDRESS && Address_MB < FIRMWARE_INFO_END) { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; } /* Как в контракте 167, запись в паспорт запрещена с Illegal Data Address и не достигает параметров или логгера. */
if (Address_MB >= UMP_LOG_BASE) {
if (!ump_log_write(Address_MB, Data_MB)) {
modbus_exception(rs_arr, CMD_MODBUS_6, 3); return;
}
} else if (Address_MB < ANSWER_LEN) {
/* RS и CAN используют одну историю фронтов. Чередование каналов
* не создаёт двух независимых повторных запусков. */
if (Address_MB == 127) {
UMP_commands_write(Data_MB);
ump_log_rs();
} else Modbus[Address_MB].all = Data_MB;
} else { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; }
rs_arr->flag_TIMEOUT_to_Send=true;
RS_Send(rs_arr, rs_arr->buffer, Address_MB >= UMP_LOG_BASE ? 8 : 10);
}