621 lines
21 KiB
C
621 lines
21 KiB
C
/**
|
||
**************************************************************************
|
||
* @file modbus.c
|
||
* @brief Модуль для реализации MODBUS.
|
||
**************************************************************************
|
||
* @details
|
||
Файл содержит реализацию функций работы с Modbus.
|
||
|
||
@section Функции и макросы
|
||
|
||
### Инициализация:
|
||
- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM)
|
||
- MODBUS_Config() — Конфигурацмя Modbus (ID, Timeout).
|
||
- MODBUS_SlaveStart() — Запуск Modbus как Slave.
|
||
|
||
### Функции для Modbus
|
||
- MB_Slave_Response() — Ответ на запрос
|
||
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
||
- MB_Slave_Parse_Message() — Парс сообщения в режиме слейва.
|
||
- MB_Master_Collect_Message() — Сбор сообщения в режиме мастера
|
||
- MB_Master_Parse_Message() — Парс сообщения в режиме мастера
|
||
|
||
### Функции для работы с RS (UART):
|
||
- RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
|
||
- RS_Response() — Отправка ответа.
|
||
******************************************************************************/
|
||
#include "modbus.h"
|
||
|
||
/* MODBUS HANDLES */
|
||
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
|
||
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
|
||
|
||
/* DEFINE DATA FOR MODBUS */
|
||
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
|
||
|
||
//-------------------------------------------------------------------
|
||
//-----------------------------FOR USER------------------------------
|
||
/**
|
||
* @brief Инициализация периферии модбас.
|
||
* @param hmodbus Указатель на хендлер RS
|
||
* @param huart Указатель на хендлер UART
|
||
* @param htim Указатель на хендлер TIM
|
||
* @details Подключает хендлы периферии к hmodbus
|
||
* Конфигурация выставляется по умолчанию из modbus_config.h
|
||
*/
|
||
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
|
||
{
|
||
if((hmodbus == NULL) || (huart == NULL))
|
||
{
|
||
return HAL_ERROR;
|
||
}
|
||
MB_DeviceInentificationInit();
|
||
//-----------SETUP MODBUS-------------
|
||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||
hmodbus->ID = MODBUS_DEVICE_ID;
|
||
hmodbus->sRS_Timeout = MODBUS_TIMEOUT;
|
||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||
hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst;
|
||
|
||
// INIT
|
||
hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
|
||
|
||
RS_EnableReceive();
|
||
|
||
if(hmodbus->RS_STATUS == RS_OK)
|
||
return HAL_OK;
|
||
else
|
||
return HAL_ERROR;
|
||
}
|
||
/**
|
||
* @brief Программная конфигурация модбас.
|
||
* @param hmodbus указатель на хендлер RS
|
||
* @param Timeout Время тишины между двумя байтами после которых перезапускается прием
|
||
* @param master Режим мастер (пока не сделан)
|
||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||
*/
|
||
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
|
||
{
|
||
if(hmodbus == NULL)
|
||
{
|
||
return HAL_ERROR;
|
||
}
|
||
if((ID < 1) || (ID > 247))
|
||
{
|
||
return HAL_ERROR;
|
||
}
|
||
//-----------SETUP MODBUS-------------
|
||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||
hmodbus->ID = ID;
|
||
hmodbus->sRS_Timeout = Timeout;
|
||
if(master)
|
||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||
else
|
||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||
hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst;
|
||
|
||
return HAL_OK;
|
||
}
|
||
|
||
/**
|
||
* @brief Запуск слейв модбас.
|
||
* @param hmodbus Указатель на хендлер RS.
|
||
* @param modbus_msg Указатель на структуру сообщения.
|
||
(NULL чтобы использовать дефолтную)
|
||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||
*/
|
||
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||
{
|
||
if(hmodbus == NULL)
|
||
{
|
||
return HAL_ERROR;
|
||
}
|
||
|
||
if(hmodbus->sRS_Mode >= RS_MASTER_START)
|
||
{
|
||
return HAL_ERROR;
|
||
}
|
||
|
||
MB_DiagnosticsInit();
|
||
|
||
if(modbus_msg)
|
||
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, modbus_msg);
|
||
else
|
||
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, &MODBUS_MSG);
|
||
|
||
if(hmodbus->RS_STATUS == RS_OK)
|
||
return HAL_OK;
|
||
else
|
||
return HAL_ERROR;
|
||
}
|
||
|
||
|
||
|
||
|
||
//-------------------------------------------------------------------
|
||
//-----------------------------INTERNAL------------------------------
|
||
|
||
/**
|
||
* @brief Ответ на сообщение в режиме слейва.
|
||
* @param hmodbus Указатель на хендлер RS.
|
||
* @param modbus_msg Указатель на структуру сообщения.
|
||
* @return RS_RES Статус о результате ответа на комманду.
|
||
*/
|
||
static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||
{
|
||
RS_StatusTypeDef MB_RES = 0;
|
||
hmodbus->f.MessageHandled = 0;
|
||
hmodbus->f.EchoResponse = 0;
|
||
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
|
||
|
||
MB_Diagnostics_BusMessageCnt();
|
||
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0)
|
||
{
|
||
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
|
||
hmodbus->RS_STATUS = RS_SKIP;
|
||
return RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||
}
|
||
MB_Diagnostics_SlaveMessageCnt();
|
||
|
||
if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing
|
||
{
|
||
switch (modbus_msg->Func_Code)
|
||
{
|
||
// Read Coils
|
||
case MB_R_COILS:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Read_Coils(hmodbus->pMessagePtr);
|
||
break;
|
||
|
||
// Read Hodling Registers
|
||
case MB_R_HOLD_REGS:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Read_Hold_Regs(hmodbus->pMessagePtr);
|
||
break;
|
||
case MB_R_IN_REGS:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Read_Input_Regs(hmodbus->pMessagePtr);
|
||
break;
|
||
|
||
|
||
// Write Single Coils
|
||
case MB_W_COIL:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Coil(hmodbus->pMessagePtr);
|
||
if(hmodbus->f.MessageHandled)
|
||
{
|
||
hmodbus->f.DataUpdated = 1;
|
||
hmodbus->f.EchoResponse = 1;
|
||
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
||
}
|
||
break;
|
||
|
||
case MB_W_HOLD_REG:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Reg(hmodbus->pMessagePtr);
|
||
if(hmodbus->f.MessageHandled)
|
||
{
|
||
hmodbus->f.DataUpdated = 1;
|
||
hmodbus->f.EchoResponse = 1;
|
||
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
||
}
|
||
break;
|
||
|
||
// Write Multiple Coils
|
||
case MB_W_COILS:
|
||
hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr);
|
||
if(hmodbus->f.MessageHandled)
|
||
{
|
||
hmodbus->f.DataUpdated = 1;
|
||
hmodbus->f.EchoResponse = 1;
|
||
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
||
}
|
||
break;
|
||
|
||
// Write Multiple Registers
|
||
case MB_W_HOLD_REGS:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Write_Miltuple_Regs(hmodbus->pMessagePtr);
|
||
if(hmodbus->f.MessageHandled)
|
||
{
|
||
hmodbus->f.DataUpdated = 1;
|
||
hmodbus->f.EchoResponse = 1;
|
||
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
||
}
|
||
break;
|
||
|
||
case MB_R_DEVICE_INFO:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Read_Device_Identification(hmodbus->pMessagePtr);
|
||
break;
|
||
|
||
// Добавить в switch-case после других case:
|
||
case MB_R_DIAGNOSTIC:
|
||
hmodbus->f.MessageHandled = MB_Proccess_Diagnostics(hmodbus->pMessagePtr);
|
||
break;
|
||
|
||
/* unknown func code */
|
||
default:
|
||
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||
}
|
||
|
||
|
||
// Проверяем режим устройства - если Listen Only, не обрабатываем команды
|
||
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
|
||
{
|
||
MB_Diagnostics_SlaveNoResponseCnt();
|
||
hmodbus->RS_STATUS = RS_SKIP;
|
||
return RS_Handle_Receive_Start(hmodbus, modbus_msg);;
|
||
}
|
||
|
||
// Проверяем статус обработки запроса
|
||
if(hmodbus->f.MessageHandled == 0)
|
||
{
|
||
MB_Diagnostics_ExceptionErrorCnt();
|
||
TrackerCnt_Warn(hmodbus->rs_err);
|
||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||
}
|
||
else
|
||
{
|
||
TrackerCnt_Ok(hmodbus->rs_err);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
// if we need response - check that transmit isnt busy
|
||
if( RS_Is_TX_Busy(hmodbus) )
|
||
RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free
|
||
|
||
// Transmit right there, or sets (fDeferredResponse) to transmit response in main code
|
||
if(hmodbus->f.DeferredResponse == 0)
|
||
{
|
||
MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg);
|
||
}
|
||
else
|
||
{
|
||
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||
hmodbus->f.DeferredResponse = 0;
|
||
}
|
||
|
||
hmodbus->RS_STATUS = MB_RES;
|
||
return MB_RES;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief Сбор сообщения в буфер UART в режиме слейв.
|
||
* @param hmodbus Указатель на хендлер RS.
|
||
* @param modbus_msg Указатель на структуру сообщения.
|
||
* @param modbus_uart_buff Указатель на буффер UART.
|
||
* @return RS_RES Статус о результате заполнения буфера.
|
||
*/
|
||
static RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||
{
|
||
int ind = 0; // ind for modbus-uart buffer
|
||
|
||
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
|
||
ind = hmodbus->RS_Message_Size;
|
||
else
|
||
{
|
||
//------INFO ABOUT DATA/MESSAGE------
|
||
//-----------[first bytes]-----------
|
||
// set ID of message/user
|
||
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
||
|
||
// set dat or err response
|
||
modbus_uart_buff[ind++] = modbus_msg->Func_Code;
|
||
|
||
if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur
|
||
{
|
||
// fill modbus header
|
||
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identification header
|
||
{
|
||
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
||
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
||
modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity;
|
||
modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows;
|
||
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
|
||
modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj;
|
||
|
||
if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
||
{
|
||
TrackerCnt_Err(hmodbus->rs_err);
|
||
return RS_COLLECT_MSG_ERR;
|
||
}
|
||
|
||
|
||
//---------------DATA----------------
|
||
//-----------[data bytes]------------
|
||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
||
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
||
{ // set data
|
||
modbus_uart_buff[ind++] = *tmp_data_addr;
|
||
tmp_data_addr++;
|
||
}
|
||
|
||
}
|
||
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||
{
|
||
// Diagnostics special format: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||
modbus_uart_buff[ind++] = modbus_msg->DATA[0] >> 8; // Sub-function HI
|
||
modbus_uart_buff[ind++] = modbus_msg->DATA[0] & 0xFF; // Sub-function LO
|
||
modbus_uart_buff[ind++] = modbus_msg->DATA[1] >> 8; // Data HI
|
||
modbus_uart_buff[ind++] = modbus_msg->DATA[1] & 0xFF; // Data LO
|
||
}
|
||
else // modbus data header
|
||
{
|
||
// set size of received data
|
||
if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
||
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
||
else // otherwise return data_size err
|
||
{
|
||
TrackerCnt_Err(hmodbus->rs_err);
|
||
return RS_COLLECT_MSG_ERR;
|
||
}
|
||
|
||
//---------------DATA----------------
|
||
//-----------[data bytes]------------
|
||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
||
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
||
{ // set data
|
||
if (i%2 == 0) // HI byte
|
||
modbus_uart_buff[ind++] = (*tmp_data_addr)>>8;
|
||
else // LO byte
|
||
{
|
||
modbus_uart_buff[ind++] = *tmp_data_addr;
|
||
tmp_data_addr++;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
else // if some error occur
|
||
{ // send expection code
|
||
modbus_uart_buff[ind++] = modbus_msg->Except_Code;
|
||
}
|
||
}
|
||
if(ind < 0)
|
||
return RS_COLLECT_MSG_ERR;
|
||
|
||
//---------------CRC----------------
|
||
//---------[last 16 bytes]----------
|
||
// calc crc of received data
|
||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||
// write crc to message structure and modbus-uart buffer
|
||
modbus_msg->MB_CRC = CRC_VALUE;
|
||
modbus_uart_buff[ind++] = CRC_VALUE;
|
||
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
||
|
||
hmodbus->RS_Message_Size = ind;
|
||
|
||
return RS_OK; // returns ok
|
||
}
|
||
|
||
/**
|
||
* @brief Определить размер модбас запроса.
|
||
* @param hRS Указатель на хендлер RS.
|
||
* @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия.
|
||
* @return RS_RES Статус о корректности рассчета кол-ва байт для принятия.
|
||
* @details Определение сколько байтов надо принять по протоколу.
|
||
*/
|
||
static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||
{
|
||
RS_StatusTypeDef MB_RES = 0;
|
||
int mb_func_size = 0;
|
||
|
||
if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||
{
|
||
mb_func_size = 1;
|
||
}
|
||
else if(modbus_msg->Func_Code == MB_R_DEVICE_INFO)
|
||
{
|
||
mb_func_size = 0;
|
||
}
|
||
else if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F)
|
||
{
|
||
mb_func_size = 1;
|
||
}
|
||
else
|
||
{
|
||
mb_func_size = modbus_msg->ByteCnt + 2;
|
||
}
|
||
|
||
|
||
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
|
||
return mb_func_size;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief Парс сообщения в режиме слейв.
|
||
* @param hmodbus Указатель на хендлер RS.
|
||
* @param modbus_msg Указатель на структуру сообщения.
|
||
* @param modbus_uart_buff Указатель на буффер UART.
|
||
* @return RS_RES Статус о результате заполнения структуры.
|
||
* @details Заполнение структуры сообщения из буффера UART.
|
||
*/
|
||
static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||
{
|
||
uint32_t check_empty_buff;
|
||
int ind = 0; // ind for modbus-uart buffer
|
||
hmodbus->f.RX_Continue = 0;
|
||
int expected_size = 0;
|
||
//-----INFO ABOUT DATA/MESSAGE-------
|
||
//-----------[first bits]------------
|
||
// get ID of message/user
|
||
if(modbus_uart_buff[ind] != hmodbus->ID)
|
||
{
|
||
modbus_msg->MbAddr = 0;
|
||
ind++;
|
||
}
|
||
else
|
||
{
|
||
modbus_msg->MbAddr = modbus_uart_buff[ind++];
|
||
}
|
||
|
||
// get func code
|
||
modbus_msg->Func_Code = modbus_uart_buff[ind++];
|
||
if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня
|
||
{
|
||
MB_Diagnostics_SlaveNAKCnt();
|
||
modbus_msg->MbAddr = 0;
|
||
return RS_SKIP;
|
||
}
|
||
|
||
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request
|
||
{
|
||
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
|
||
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
|
||
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
|
||
modbus_msg->ByteCnt = 0;
|
||
}
|
||
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||
{
|
||
// Diagnostics: читаем 4 байта в DATA[0] и DATA[1]
|
||
// Sub-function
|
||
modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8;
|
||
modbus_msg->DATA[0] |= modbus_uart_buff[ind++];
|
||
// Data
|
||
modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8;
|
||
modbus_msg->DATA[1] |= modbus_uart_buff[ind++];
|
||
modbus_msg->Addr = 0; // не использует Addr
|
||
modbus_msg->Qnt = 0; // не использует Qnt
|
||
}
|
||
else // if its classic modbus request
|
||
{
|
||
// get address from CMD
|
||
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
||
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
||
|
||
// get address from CMD
|
||
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
||
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
||
}
|
||
|
||
if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10))
|
||
hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++];
|
||
else
|
||
hmodbus->pMessagePtr->ByteCnt = 0;
|
||
|
||
expected_size = MB_Define_Size_of_Function(hmodbus, modbus_msg);
|
||
// если размер меньше ожидаемого - продолжаем принимать
|
||
if(hmodbus->RS_Message_Size < expected_size)
|
||
{
|
||
hmodbus->f.RX_Continue = 1;
|
||
return RS_SKIP;
|
||
}
|
||
// если больше Ошибка
|
||
else if (hmodbus->RS_Message_Size > expected_size)
|
||
{
|
||
MB_Diagnostics_CommunicationErrorCnt();
|
||
return RS_PARSE_MSG_ERR;
|
||
}
|
||
|
||
//---------------DATA----------------
|
||
// (optional)
|
||
if (modbus_msg->ByteCnt != 0)
|
||
{
|
||
//check that data size is correct
|
||
if (modbus_msg->ByteCnt > DATA_SIZE*2)
|
||
{
|
||
TrackerCnt_Err(hmodbus->rs_err);
|
||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||
MB_Diagnostics_CommunicationErrorCnt();
|
||
return RS_PARSE_MSG_ERR;
|
||
}
|
||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||
{ // set data
|
||
if (i%2 == 0)
|
||
*tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8);
|
||
else
|
||
{
|
||
*tmp_data_addr |= modbus_uart_buff[ind++];
|
||
tmp_data_addr++;
|
||
}
|
||
}
|
||
}
|
||
|
||
//---------------CRC----------------
|
||
//----------[last 16 bits]----------
|
||
// calc crc of received data
|
||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||
// get crc of received data
|
||
modbus_msg->MB_CRC = modbus_uart_buff[ind++];
|
||
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8;
|
||
// compare crc
|
||
if (modbus_msg->MB_CRC != CRC_VALUE)
|
||
{
|
||
MB_Diagnostics_CommunicationErrorCnt();
|
||
TrackerCnt_Err(hmodbus->rs_err);
|
||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||
}
|
||
|
||
return RS_OK;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
* @brief Сбор сообщения в буфер UART в режиме мастер.
|
||
* @param hmodbus Указатель на хендлер RS.
|
||
* @param modbus_msg Указатель на структуру сообщения.
|
||
* @param modbus_uart_buff Указатель на буффер UART.
|
||
* @return RS_RES Статус о результате заполнения буфера.
|
||
*/
|
||
static RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||
{
|
||
return RS_PARSE_MSG_ERR;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief Парс сообщения в режиме мастер.
|
||
* @param hmodbus Указатель на хендлер RS.
|
||
* @param modbus_msg Указатель на структуру сообщения.
|
||
* @param modbus_uart_buff Указатель на буффер UART.
|
||
* @return RS_RES Статус о результате заполнения структуры.
|
||
*/
|
||
static RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||
{
|
||
return RS_PARSE_MSG_ERR;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/* Реализация функций из rs_message.c для протокола */
|
||
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||
{
|
||
if(hmodbus->sRS_Mode >= RS_MASTER_START)
|
||
{
|
||
return RS_ERR;
|
||
}
|
||
return MB_Slave_Response(hmodbus, modbus_msg);
|
||
}
|
||
|
||
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||
{
|
||
if(hmodbus->sRS_Mode < RS_MASTER_START)
|
||
{
|
||
return MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||
}
|
||
else
|
||
{
|
||
return MB_Master_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||
}
|
||
}
|
||
|
||
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||
{
|
||
if(hmodbus->sRS_Mode < RS_MASTER_START)
|
||
{
|
||
return MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||
}
|
||
else
|
||
{
|
||
return MB_Master_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||
}
|
||
} |