Files
Balsam_167/Source/Internal/message.c

343 lines
9.8 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.
/**
* @file message.c
* @brief Параметры устройства и прикладные сообщения протокола Modbus.
*
* Инициализирует значения по умолчанию, загружает и сохраняет параметры в
* EEPROM, принимает команды функций 3/6 и формирует ответы функции 4.
* Индексы param/Modbus согласованы с внешней картой регистров; менять порядок,
* ANSWER_LEN или представление слов можно только вместе с ведущей системой.
*/
#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 "caliber.h"
/** @brief Рабочий образ регистров Modbus, передаваемый внешнему мастеру. */
int modbus[ANSWER_LEN+1];
/** @brief Сохраняемые параметры, индексно согласованные с картой регистров. */
unsigned int param[ANSWER_LEN+1];
/**
* @brief Создаёт полный набор безопасных параметров для текущего варианта платы.
* @post Modbus/param, режимы, пороги, яркость и калибровки имеют штатные значения.
* @details Начальная очистка предотвращает сохранение мусора в зарезервированных
* регистрах; далее значения выбираются по Desk и compile-time конфигурации.
*/
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++)
{
Modbus[i].all = 0;
}
LastMode = Mode;
if(Desk == dsk_EPLT)
{
Cancount[m_FAST] = 2; // пауза между посылками CAN
for(i=0;i<6;i++) Bright[i] = bright[i];
}
else
{
Cancount[m_FAST] = 10; // пауза между посылками CAN
Brightness = 8;
}
Cancount[m_SLOW] = 101; // пауза между посылками CAN
if(Owen) Owncount = 20; // пауза между опросами OWEN
if(Kalibro)
{
#ifdef CALIB_RS
def = Mode-1;
if(Mode>adr_PULT) def--;
#else
def = Mode-3;
if(Mode==adr_SHKF) def=4;
#endif
for(i=0;i<8;i++) Caliber[i] = def_cal[def][i];
}
if(Desk == dsk_COMM)
{
for(i=0;i<TPL_POW*2+Owen;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();
}
/**
* @brief Загружает параметрический блок из EEPROM и проверяет его целостность.
* @details При несовпадении сигнатуры/CRC вызывается Default_params(); после
* успешной загрузки значения переносятся в рабочие глобальные настройки.
*/
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]) )
{
for(i=0;i<ANSWER_LEN;i++) modbus[i] = param[i];
Commands=0;
}
else
{
Default_params();
Commands=0;
Save_params();
if(TermoSW)
{
cTermoCal =1;
Caliber_time = 0xFFFF;
} } }
/**
* @brief Формирует параметрический блок с CRC и записывает его в EEPROM.
* @warning Запись следует запускать только при свободном драйвере EEPROM;
* питание должно сохраняться до физического завершения транзакции.
*/
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
Чтение ачеек данных */
/***************************************************************/
/***************************************************************/
/**
* @brief Обрабатывает запрос Modbus чтения диапазона регистров.
* @param rs_arr Порт с проверенным входным кадром и буфером ответа.
* @details Проверяет начальный адрес и длину, копирует слова из modbus и
* формирует CRC непосредственно перед отправкой.
*/
void ReceiveCommandModbus3(RS_DATA *rs_arr)
{
unsigned int crc, Address_MB, Length_MB, i;
// получили начальный адрес чтениа
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];
/////////////////////////////////////////////////
// Отсылка
/* Посчитали контрольную сумму перед самой посылкой */
rs_arr->buffer[0] = CNTRL_ADDR;
rs_arr->buffer[1] = CMD_MODBUS_3;
rs_arr->buffer[2] = Length_MB*2;
for (i=0;i<Length_MB;i++)
{
rs_arr->buffer[3+i*2 ]=(Modbus[Address_MB+i].byt.byte_hi);
rs_arr->buffer[3+i*2+1]=(Modbus[Address_MB+i].byt.byte_lo);
}
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;
RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+8);
return;
}
/**
* @brief Применяет команду записи одного параметра Modbus.
* @details После проверки адреса обновляет разрешённое значение, выставляет
* события перенастройки/сохранения и возвращает эхо принятой команды.
*/
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];
Modbus[Address_MB].all = Data_MB;
rs_arr->flag_TIMEOUT_to_Send=true;
RS_Send(rs_arr, rs_arr->buffer, 10);
}
/**
* @brief Формирует периодический запрос/ответ функции 4 для внешнего устройства.
* @details Адрес, полезная нагрузка и CRC помещаются в буфер выбранного RS-порта,
* после чего передача запускается неблокирующим RS_Send().
*/
void SendCommandModbus4(RS_DATA *rs_arr)
{
unsigned int crc;
/////////////////////////////////////////////////
// Отсылка
rs_arr->buffer[0] = 16;
rs_arr->buffer[1] = 4;
rs_arr->buffer[2] = 0;
rs_arr->buffer[3] = 0;
rs_arr->buffer[4] = 0;
rs_arr->buffer[5] = 48;
crc = 0xffff;
crc = get_crc_16(crc, rs_arr->buffer, 6);
rs_arr->buffer[6] = LOBYTE(crc);
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_Send(rs_arr, rs_arr->buffer, 8);
}
/**
* @brief Разбирает ответ внешнего измерителя на функцию Modbus 4.
* @details Проверяет формат и переносит температуры/диагностики в ext_temp и
* ext_diag; некорректный ответ не должен заменять последний пригодный снимок.
*/
void ReceiveAnswerModbus4(RS_DATA *rs_arr)
{
unsigned int i;
/////////////////////////////////////////////////
// Отсылка
for (i=0;i<8;i++)
{
ext_temp[i] = ( rs_arr->RS_Header[5+i*12] << 8) +
rs_arr->RS_Header[6+i*12];
ext_diag[i] = ( rs_arr->RS_Header[7+i*12] |
rs_arr->RS_Header[8+i*12] ) != 0;
} }