Подтягивание всех изменений с релиза в ветку
This commit is contained in:
@@ -9,58 +9,58 @@
|
||||
@section Функции и макросы
|
||||
|
||||
### Инициализация:
|
||||
- MODBUS_SetupHardware() — Инициализация модуля Modbus.
|
||||
- MODBUS_Config() — Инициализация модуля Modbus.
|
||||
|
||||
### Функции для Modbus
|
||||
- MB_Slave_Response()
|
||||
- MB_Slave_Collect_Message()
|
||||
- MB_Slave_Parse_Message()
|
||||
- MB_Master_Collect_Message()
|
||||
- MB_Master_Parse_Message()
|
||||
- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM)
|
||||
- MODBUS_Config() — Конфигурацмя Modbus (ID, Timeout).
|
||||
- MODBUS_SlaveStart() — Запуск Modbus как Slave.
|
||||
- MODBUS_MasterRequest() — Отправить запрос в MODBUS как Master.
|
||||
|
||||
### Функции для работы с RS (UART):
|
||||
- RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
|
||||
- RS_Response() — Отправка ответа.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
/* MODBUS HANDLES */
|
||||
RS_HandleTypeDef hmodbus1;
|
||||
RS_MsgTypeDef MODBUS_MSG;
|
||||
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
|
||||
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
|
||||
|
||||
/* DEFINE REGISTERS/COILS */
|
||||
MB_DeviceIdentificationTypeDef MB_DEVID;
|
||||
MB_DataStructureTypeDef MB_DATA = {0};;
|
||||
/* DEFINE DATA FOR MODBUS */
|
||||
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
|
||||
|
||||
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------FOR USER------------------------------
|
||||
/**
|
||||
* @brief Инициализация периферии модбас.
|
||||
* @param hmodbus Указатель на хендлер RS
|
||||
* @param huart Указатель на хендлер UART
|
||||
* @param htim Указатель на хендлер TIM
|
||||
* @details Подключает хендлы периферии к hmodbus
|
||||
* Конфигурация выставляется по умолчанию из modbus_config.h
|
||||
*/
|
||||
void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
|
||||
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
|
||||
{
|
||||
if((hmodbus == NULL) || (huart == NULL))
|
||||
{
|
||||
return;
|
||||
return HAL_ERROR;
|
||||
}
|
||||
MB_DeviceInentificationInit();
|
||||
//-----------SETUP MODBUS-------------
|
||||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||||
hmodbus1.ID = MODBUS_DEVICE_ID;
|
||||
hmodbus1.sRS_Timeout = MODBUS_TIMEOUT;
|
||||
hmodbus1.sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||
hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst;
|
||||
hmodbus->ID = MODBUS_DEVICE_ID;
|
||||
hmodbus->sRS_Timeout = MODBUS_TIMEOUT;
|
||||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||
|
||||
// INIT
|
||||
hmodbus1.RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
|
||||
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 Программная конфигурация модбас.
|
||||
@@ -69,460 +69,115 @@ void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart,
|
||||
* @param master Режим мастер (пока не сделан)
|
||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||
*/
|
||||
void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
|
||||
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
|
||||
{
|
||||
if(hmodbus == NULL)
|
||||
{
|
||||
return;
|
||||
return HAL_ERROR;
|
||||
}
|
||||
//-----------SETUP MODBUS-------------
|
||||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||||
hmodbus->ID = ID;
|
||||
if(!master)
|
||||
{
|
||||
if((ID < 1) || (ID > 247))
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
hmodbus->ID = ID;
|
||||
}
|
||||
else
|
||||
hmodbus->ID = 0;
|
||||
|
||||
hmodbus->sRS_Timeout = Timeout;
|
||||
if(master)
|
||||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||
hmodbus->sRS_Mode = RS_MASTER_REQUEST;
|
||||
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 Указатель на структуру сообщения.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
(NULL чтобы использовать дефолтную)
|
||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||
*/
|
||||
void MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
if(hmodbus == NULL)
|
||||
{
|
||||
return;
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
MB_DiagnosticsInit();
|
||||
|
||||
if(modbus_msg)
|
||||
RS_Receive_IT(hmodbus, modbus_msg);
|
||||
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, modbus_msg);
|
||||
else
|
||||
RS_Receive_IT(hmodbus, &MODBUS_MSG);
|
||||
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, &MODBUS_MSG);
|
||||
|
||||
if(hmodbus->RS_STATUS == RS_OK)
|
||||
return HAL_OK;
|
||||
else
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Ответ на сообщение в режиме слейва.
|
||||
* @brief Реквест мастера модбас.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о результате ответа на комманду.
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||
*/
|
||||
static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*))
|
||||
{
|
||||
RS_StatusTypeDef MB_RES = 0;
|
||||
hmodbus->f.MessageHandled = 0;
|
||||
hmodbus->f.EchoResponse = 0;
|
||||
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
|
||||
|
||||
if(hmodbus->ID == 0)
|
||||
if(hmodbus == NULL)
|
||||
{
|
||||
hmodbus->RS_STATUS = RS_SKIP;
|
||||
return MB_RES;
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing
|
||||
if(modbus_msg == NULL)
|
||||
{
|
||||
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;
|
||||
|
||||
/* unknown func code */
|
||||
default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||
}
|
||||
|
||||
if(hmodbus->f.MessageHandled == 0)
|
||||
{
|
||||
TrackerCnt_Warn(hmodbus->rs_err);
|
||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrackerCnt_Ok(hmodbus->rs_err);
|
||||
}
|
||||
|
||||
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 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
|
||||
if(hmodbus->f.RS_Busy)
|
||||
return HAL_BUSY;
|
||||
|
||||
if(pClbk) // если задан используем пользовательский коллбек
|
||||
hmodbus->pCallback = (void (*)(void*, void*))(pClbk);
|
||||
else // иначе дефолтный
|
||||
hmodbus->pCallback = (void (*)(void*, void*))(&MB_DefaultCallback);
|
||||
|
||||
// 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);
|
||||
}
|
||||
hmodbus->RS_STATUS = RS_Transmit_IT(hmodbus, modbus_msg);
|
||||
|
||||
if(hmodbus->RS_STATUS == RS_OK)
|
||||
return HAL_OK;
|
||||
else
|
||||
{
|
||||
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||
hmodbus->f.DeferredResponse = 0;
|
||||
}
|
||||
|
||||
hmodbus->RS_STATUS = MB_RES;
|
||||
return MB_RES;
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @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)
|
||||
|
||||
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
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 // 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
|
||||
__NOP();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 & ~ERR_VALUES_START) < 0x0F)
|
||||
{
|
||||
modbus_msg->ByteCnt = 0;
|
||||
mb_func_size = 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
modbus_msg->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command
|
||||
// +1 because that defines is size, not ind.
|
||||
mb_func_size = modbus_msg->ByteCnt + 2;
|
||||
}
|
||||
|
||||
|
||||
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO)
|
||||
{
|
||||
mb_func_size = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
//-----INFO ABOUT DATA/MESSAGE-------
|
||||
//-----------[first bits]------------
|
||||
// get ID of message/user
|
||||
if(modbus_uart_buff[ind] != hmodbus->ID)
|
||||
{
|
||||
modbus_msg->MbAddr = 0;
|
||||
return RS_SKIP;
|
||||
}
|
||||
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) // явная херня
|
||||
{
|
||||
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 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;
|
||||
|
||||
//---------------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;
|
||||
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)
|
||||
{
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||||
}
|
||||
// hmodbus->MB_RESPONSE = MB_CRC_ERR; // set func code - error about wrong crc
|
||||
|
||||
// check is buffer empty
|
||||
check_empty_buff = 0;
|
||||
for(int i=0; i<ind;i++)
|
||||
check_empty_buff += modbus_uart_buff[i];
|
||||
// if(check_empty_buff == 0)
|
||||
// hmodbus->MB_RESPONSE = MB_EMPTY_MSG; //
|
||||
|
||||
// если размер меньше ожидаемого - продолжаем принимать
|
||||
if(hmodbus->RS_Message_Size < MB_Define_Size_of_Function(hmodbus, modbus_msg))
|
||||
{
|
||||
hmodbus->f.RX_Continue = 1;
|
||||
return RS_SKIP;
|
||||
}
|
||||
// если больше Ошибка
|
||||
else if (hmodbus->RS_Message_Size > MB_Define_Size_of_Function(hmodbus, modbus_msg))
|
||||
{
|
||||
return RS_PARSE_MSG_ERR;
|
||||
}
|
||||
|
||||
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)
|
||||
if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START)
|
||||
{
|
||||
return RS_ERR;
|
||||
}
|
||||
@@ -531,7 +186,7 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms
|
||||
|
||||
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_START)
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
return MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||
}
|
||||
@@ -543,7 +198,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo
|
||||
|
||||
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_START)
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
return MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
******************************************************************************/
|
||||
#include "modbus_coils.h"
|
||||
|
||||
|
||||
#ifdef MODBUS_ENABLE_COILS
|
||||
|
||||
/**
|
||||
* @brief Set or Reset Coil at its global address.
|
||||
* @brief Выставить/сбросить коил по глобальному адресу.
|
||||
* @param Addr Адрес коила.
|
||||
* @param WriteVal Что записать в коил: 0 или 1.
|
||||
* @return ExceptionCode Код исключения если коила по адресу не существует, и NO_ERRORS если все ок.
|
||||
@@ -55,7 +55,7 @@ MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteV
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read Coil at its global address.
|
||||
* @brief Считать коил по глобальному адресу.
|
||||
* @param Addr Адрес коила.
|
||||
* @param Exception Указатель на переменную для кода исключения, в случа неудачи при чтении.
|
||||
* @return uint16_t Возвращает весь регистр с маской на запрошенном коиле.
|
||||
@@ -86,13 +86,48 @@ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Proccess command Read Coils (01 - 0x01).
|
||||
|
||||
/**
|
||||
* @brief Получить состояние coil в ответе по его адресу
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param coil_addr Адрес coil, состояние которого нужно получить
|
||||
* @param coil_state Указатель для состояния coil (1 - ON, 0 - OFF)
|
||||
* @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса
|
||||
*/
|
||||
int MB_GetCoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state)
|
||||
{
|
||||
if(modbus_msg == NULL || coil_state == NULL)
|
||||
return 0;
|
||||
|
||||
// Проверяем что coil_addr в пределах запрошенного диапазона
|
||||
if(coil_addr < modbus_msg->Addr || coil_addr >= modbus_msg->Addr + modbus_msg->Qnt)
|
||||
return 0;
|
||||
|
||||
// Вычисляем индекс coil в полученных данных
|
||||
uint16_t coil_index = coil_addr - modbus_msg->Addr;
|
||||
|
||||
// Вычисляем байт и бит
|
||||
uint8_t byte_index = coil_index / 8;
|
||||
uint8_t bit_index = coil_index % 8;
|
||||
|
||||
// Проверяем что байт существует в данных
|
||||
if(byte_index >= modbus_msg->ByteCnt)
|
||||
return 0;
|
||||
|
||||
// Получаем байт и проверяем бит
|
||||
uint8_t coil_byte = modbus_msg->DATA[byte_index] & 0xFF;
|
||||
*coil_state = (coil_byte >> bit_index) & 0x01;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Read Coils (01 - 0x01).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Read Coils.
|
||||
*/
|
||||
uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
uint16_t *coils;
|
||||
@@ -140,12 +175,12 @@ uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Proccess command Write Single Coils (05 - 0x05).
|
||||
* @brief Обработать функцию Write Single Coils (05 - 0x05).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Single Coils.
|
||||
*/
|
||||
uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
|
||||
@@ -171,7 +206,7 @@ uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Proccess command Write Multiple Coils (15 - 0x0F).
|
||||
* @brief Обработать функцию Write Multiple Coils (15 - 0x0F).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Multiple Coils.
|
||||
@@ -236,3 +271,14 @@ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else //MODBUS_ENABLE_COILS
|
||||
|
||||
|
||||
int MB_GetCoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) {return 0;}
|
||||
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal) {return ILLEGAL_FUNCTION;}
|
||||
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) {return 0;}
|
||||
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
|
||||
#endif
|
||||
@@ -77,7 +77,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
|
||||
// Default holding registers
|
||||
if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS)
|
||||
{
|
||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr); // указатель на выбранный по Addr регистр
|
||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр
|
||||
}
|
||||
// if address doesnt match any array - return illegal data address response
|
||||
else
|
||||
@@ -90,7 +90,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
|
||||
// Default input registers
|
||||
if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS)
|
||||
{
|
||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr); // указатель на выбранный по Addr регистр
|
||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr - R_INPUT_ADDR); // указатель на выбранный по Addr регистр
|
||||
}
|
||||
// if address doesnt match any array - return illegal data address response
|
||||
else
|
||||
@@ -128,7 +128,7 @@ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint
|
||||
// Default coils
|
||||
if(MB_Check_Address_For_Arr(Addr, Qnt, C_COILS_ADDR, C_COILS_QNT) == NO_ERRORS)
|
||||
{
|
||||
*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr); // указатель на выбранный по Addr массив коилов
|
||||
*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr - C_COILS_ADDR); // указатель на выбранный по Addr массив коилов
|
||||
}
|
||||
// if address doesnt match any array - return illegal data address response
|
||||
else
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_devid.c
|
||||
* @brief Реализация идентификации устройства Modbus
|
||||
* @brief Реализация идентификаторов устройства Modbus
|
||||
******************************************************************************
|
||||
* @details
|
||||
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
|
||||
@@ -14,15 +14,124 @@
|
||||
сообщений с установкой флага MoreFollows и указанием NextObjId для
|
||||
продолжения чтения в следующем запросе.
|
||||
******************************************************************************/
|
||||
|
||||
#include "modbus_devid.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
|
||||
MB_DeviceIdentificationsTypeDef MB_DEVID; ///< Глобальная структура идентификаторов устройства
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить количество объектов в сообщении
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @return int Количество объектов
|
||||
*/
|
||||
int MB_GetNumberOfObjects(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
return modbus_msg->DevId.NumbOfObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Найти объект по ID в сообщении
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param obj_id ID искомого объекта
|
||||
* @param obj_data Буфер для данных объекта (может быть NULL)
|
||||
* @param obj_length Указатель для длины объекта
|
||||
* @return int Найден ли объект (1 - да, 0 - нет)
|
||||
*/
|
||||
int MB_FindObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length)
|
||||
{
|
||||
if((modbus_msg == NULL) || (obj_data == NULL))
|
||||
return 0;
|
||||
|
||||
uint8_t *data = (uint8_t*)modbus_msg->DATA;
|
||||
unsigned ind = 0;
|
||||
|
||||
for(int i = 0; i < modbus_msg->DevId.NumbOfObj; i++)
|
||||
{
|
||||
uint8_t current_id = data[ind++];
|
||||
uint8_t current_length = data[ind++];
|
||||
|
||||
if(current_id == obj_id)
|
||||
{
|
||||
if(obj_length)
|
||||
*obj_length = current_length;
|
||||
|
||||
for(int j = 0; j < current_length; j++)
|
||||
{
|
||||
obj_data[j] = data[ind++];
|
||||
}
|
||||
obj_data[current_length] = '\0'; // добавляем \0
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Пропускаем данные этого объекта
|
||||
ind += current_length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить объект по индексу в сообщении
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param index Индекс объекта (0..N-1)
|
||||
* @param obj_id Указатель для ID объекта
|
||||
* @param obj_data Буфер для данных объекта
|
||||
* @param obj_length Указатель для длины объекта
|
||||
* @return int Успешность получения (1 - получен, 0 - не найден)
|
||||
*/
|
||||
int MB_GetObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length)
|
||||
{
|
||||
if((modbus_msg == NULL) || (obj_data == NULL))
|
||||
return 0;
|
||||
|
||||
if(index >= modbus_msg->DevId.NumbOfObj)
|
||||
return 0;
|
||||
|
||||
uint8_t *data = (uint8_t*)modbus_msg->DATA;
|
||||
unsigned ind = 0;
|
||||
|
||||
for(int i = 0; i <= index; i++)
|
||||
{
|
||||
uint8_t current_id = data[ind++];
|
||||
uint8_t current_length = data[ind++];
|
||||
|
||||
if(obj_id)
|
||||
*obj_id = current_id;
|
||||
if(obj_length)
|
||||
*obj_length = current_length;
|
||||
|
||||
if(i == index)
|
||||
{
|
||||
for(int j = 0; j < current_length; j++)
|
||||
{
|
||||
obj_data[j] = data[ind++];
|
||||
}
|
||||
obj_data[current_length] = '\0'; // добавляем \0
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Пропускаем данные этого объекта
|
||||
ind += current_length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write Object of Device Identification to MessageData
|
||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||
* @return obj Объект для записи.
|
||||
*/
|
||||
* @brief Записать Один Объект Идентификатора в массив данных
|
||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||
* @return obj Объект для записи.
|
||||
*/
|
||||
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj)
|
||||
{
|
||||
mbdata[(*ind)++] = obj->length;
|
||||
@@ -34,10 +143,10 @@ void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectT
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write Object of Device Identification to MessageData
|
||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||
* @return obj Объект для записи.
|
||||
*/
|
||||
* @brief Записать Массив Объектов Идентификатора в массив данных
|
||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||
* @return obj Объект для записи.
|
||||
*/
|
||||
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
|
||||
{
|
||||
MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID;
|
||||
@@ -85,16 +194,16 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Proccess command Read Device Identification (43/14 - 0x2B/0E).
|
||||
* @brief Обработать функцию Read Device Identifications (43/14 - 0x2B/0E).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Single Register.
|
||||
*/
|
||||
uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
switch(modbus_msg->DevId.ReadDevId)
|
||||
{
|
||||
case MB_BASIC_IDENTIFICATION:
|
||||
case MB_BASIC_IDENTIFICATIONS:
|
||||
if (modbus_msg->DevId.NextObjId == 0)
|
||||
{
|
||||
modbus_msg->DevId.NextObjId = 0;
|
||||
@@ -104,7 +213,7 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
||||
modbus_msg->DevId.NumbOfObj = 3;
|
||||
break;
|
||||
|
||||
case MB_REGULAR_IDENTIFICATION:
|
||||
case MB_REGULAR_IDENTIFICATIONS:
|
||||
if (modbus_msg->DevId.NextObjId == 0)
|
||||
{
|
||||
modbus_msg->DevId.NextObjId = 3;
|
||||
@@ -114,7 +223,12 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
||||
modbus_msg->DevId.NumbOfObj = 4;
|
||||
break;
|
||||
|
||||
case MB_EXTENDED_IDENTIFICATION:
|
||||
case MB_EXTENDED_IDENTIFICATIONS:
|
||||
if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (modbus_msg->DevId.NextObjId == 0)
|
||||
{
|
||||
modbus_msg->DevId.NextObjId = 0x80;
|
||||
@@ -124,7 +238,7 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
||||
modbus_msg->DevId.NumbOfObj = MODBUS_NUMB_OF_USEROBJECTS;
|
||||
break;
|
||||
|
||||
case MB_SPEDIFIC_IDENTIFICATION:
|
||||
case MB_SPEDIFIC_IDENTIFICATIONS:
|
||||
MB_WriteObjectsToMessage(modbus_msg, modbus_msg->DevId.NextObjId);
|
||||
modbus_msg->DevId.NumbOfObj = 1;
|
||||
break;
|
||||
@@ -136,8 +250,9 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация идентификаторов.
|
||||
*/
|
||||
void MB_DeviceInentificationInit(void)
|
||||
{
|
||||
MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME);
|
||||
@@ -533,3 +648,16 @@ void MB_DeviceInentificationInit(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#else //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
|
||||
/* Получить количество объектов в сообщении */
|
||||
int MB_GetNumberOfObjects(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
int MB_FindObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) {return 0;}
|
||||
int MB_GetObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length) {return 0;}
|
||||
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj) {}
|
||||
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) {}
|
||||
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
void MB_DeviceInentificationInit(void) {}
|
||||
|
||||
#endif
|
||||
328
Modbus/Src/modbus_diag.c
Normal file
328
Modbus/Src/modbus_diag.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_diag.c
|
||||
* @brief Реализация диагностики устройства Modbus
|
||||
******************************************************************************
|
||||
* @details
|
||||
Модуль обработки запросов диагностической информации (0x08):
|
||||
- Полная поддержка всех подфункций диагностики согласно спецификации Modbus
|
||||
- Выставление любого бита в Diagnostics Register
|
||||
- Сбор статистики работы устройства
|
||||
- Управление режимами работы (Normal/Listen Only)
|
||||
******************************************************************************/
|
||||
#include "modbus_diag.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
|
||||
MB_DiagnosticsInfoTypeDef MB_DIAG = {0}; ///< Глобальная структура диагностики
|
||||
|
||||
/**
|
||||
* @brief Инициализация диагностических счетчиков
|
||||
*/
|
||||
void MB_DiagnosticsInit(void)
|
||||
{
|
||||
MB_DIAG.DiagnosticRegister = 0;
|
||||
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
|
||||
|
||||
// Инициализация счетчиков
|
||||
MB_DIAG.Counters.BusMessage = 0;
|
||||
MB_DIAG.Counters.BusCommunicationErr = 0;
|
||||
MB_DIAG.Counters.BusExceptionErr = 0;
|
||||
MB_DIAG.Counters.SlaveMessage = 0;
|
||||
MB_DIAG.Counters.SlaveNoResponse = 0;
|
||||
MB_DIAG.Counters.SlaveNAK = 0;
|
||||
MB_DIAG.Counters.SlaveBusy = 0;
|
||||
MB_DIAG.Counters.BusCharacterOverrun = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить данные диагностики из сообщения (DATA[1])
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param data Указатель куда положить данные
|
||||
* @return 1 - успех, 0 - ошибка
|
||||
*/
|
||||
int MB_GetDiagnosticResponse(RS_MsgTypeDef *modbus_msg, uint16_t *data)
|
||||
{
|
||||
if(modbus_msg == NULL || data == NULL)
|
||||
return 0;
|
||||
|
||||
*data = modbus_msg->DATA[1];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Выставить бит в регистре диагностике
|
||||
* @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить)
|
||||
* @param bit_state Состояние бита для выставления (Выставить/Сбросить)
|
||||
* @return >0 - номер выставленного бита, 0 - ошибка
|
||||
*/
|
||||
int MB_Diagnostics_WriteBit(int bit_num, int bit_state)
|
||||
{
|
||||
if(bit_num == 0 || bit_num > 15)
|
||||
return 0;
|
||||
|
||||
if(bit_state)
|
||||
MB_DIAG.DiagnosticRegister |= (1 << bit_num);
|
||||
else
|
||||
MB_DIAG.DiagnosticRegister &= ~(1 << bit_num);
|
||||
|
||||
return bit_num;
|
||||
}
|
||||
/**
|
||||
* @brief Прочитать состояние бита диагностического регистра
|
||||
* @param bit_num Номер бита (0-15)
|
||||
* @return 1 - бит установлен, 0 - бит сброшен или ошибка
|
||||
*/
|
||||
int MB_Diagnostics_GetBit(int bit_num)
|
||||
{
|
||||
if(bit_num < 0 || bit_num > 15)
|
||||
return 0;
|
||||
|
||||
return (MB_DIAG.DiagnosticRegister >> bit_num) & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Diagnostics (Serial Line only) (0x08)
|
||||
* @param modbus_msg Указатель на структуру сообщения modbus
|
||||
* @return fMessageHandled Статус обработки команды
|
||||
*/
|
||||
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
uint16_t sub_function = modbus_msg->DATA[0];
|
||||
uint16_t request_data = modbus_msg->DATA[1];
|
||||
|
||||
// Если устройство в режиме Listen Only, отвечаем только на sub-function 0x01
|
||||
if (MB_DIAG.DeviceMode == MODBUS_LISTEN_ONLY_MODE && sub_function != 0x0001)
|
||||
{
|
||||
return 0; // Не отвечаем в режиме Listen Only
|
||||
}
|
||||
|
||||
switch(sub_function)
|
||||
{
|
||||
case 0x0000: // Return Query Data
|
||||
// Эхо-ответ с теми же данными
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = request_data;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0001: // Restart Communications
|
||||
// Перезапуск коммуникаций - выходим из Listen Only режима
|
||||
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
|
||||
|
||||
// Если request_data = 0xFF00, очищаем лог событий
|
||||
if (request_data == 0xFF00)
|
||||
{
|
||||
MB_DiagnosticsInit(); // Полный сброс
|
||||
}
|
||||
else
|
||||
{
|
||||
// Очищаем только счетчики, но не регистр диагностики
|
||||
MB_DIAG.Counters.BusMessage = 0;
|
||||
MB_DIAG.Counters.BusCommunicationErr = 0;
|
||||
MB_DIAG.Counters.BusExceptionErr = 0;
|
||||
MB_DIAG.Counters.SlaveMessage = 0;
|
||||
MB_DIAG.Counters.SlaveNoResponse = 0;
|
||||
MB_DIAG.Counters.SlaveNAK = 0;
|
||||
MB_DIAG.Counters.SlaveBusy = 0;
|
||||
MB_DIAG.Counters.BusCharacterOverrun = 0;
|
||||
}
|
||||
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = request_data;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0002: // Return Diagnostic Register
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.DiagnosticRegister;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0003: // Change ASCII Input Delimiter
|
||||
// В RTU режиме не поддерживается
|
||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||||
modbus_msg->Except_Code = ILLEGAL_FUNCTION;
|
||||
return 0;
|
||||
|
||||
case 0x0004: // Force Listen Only Mode
|
||||
MB_DIAG.DeviceMode = MODBUS_LISTEN_ONLY_MODE;
|
||||
// В режиме Listen Only не отправляем ответ
|
||||
return 0;
|
||||
|
||||
case 0x000A: // Clear Counters and Diagnostic Register
|
||||
MB_DiagnosticsInit(); // Полный сброс
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = 0;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000B: // Return Bus Message Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.BusMessage;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000C: // Return Bus Communication Error Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.BusCommunicationErr;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000D: // Return Bus Exception Error Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.BusExceptionErr;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000E: // Return Server Message Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveMessage;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000F: // Return Slave No Response Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNoResponse;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0010: // Return Slave NAK Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNAK;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0011: // Return Slave Busy Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveBusy;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0012: // Return Bus Character Overrun Count
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = MB_DIAG.Counters.BusCharacterOverrun;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0014: // Clear Overrun Counter and Flag
|
||||
MB_DIAG.Counters.BusCharacterOverrun = 0;
|
||||
// Сбрасываем флаг переполнения в DiagnosticRegister
|
||||
MB_DIAG.DiagnosticRegister &= ~(1<<0);
|
||||
modbus_msg->DATA[0] = sub_function;
|
||||
modbus_msg->DATA[1] = 0;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||||
modbus_msg->Except_Code = ILLEGAL_FUNCTION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик сообщений на шине
|
||||
*/
|
||||
void MB_Diagnostics_BusMessageCnt(void)
|
||||
{
|
||||
MB_DIAG.Counters.BusMessage++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик ошибок связи
|
||||
*/
|
||||
void MB_Diagnostics_CommunicationErrorCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.BusCommunicationErr < 0xFFFF)
|
||||
MB_DIAG.Counters.BusCommunicationErr++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик исключений
|
||||
*/
|
||||
void MB_Diagnostics_ExceptionErrorCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.BusExceptionErr < 0xFFFF)
|
||||
MB_DIAG.Counters.BusExceptionErr++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик переполнения символов
|
||||
*/
|
||||
void MB_Diagnostics_CharacterOverrunCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.BusCharacterOverrun < 0xFFFF)
|
||||
{
|
||||
MB_DIAG.Counters.BusCharacterOverrun++;
|
||||
// Устанавливаем флаг переполнения в DiagnosticRegister
|
||||
MB_DIAG.DiagnosticRegister |= (1 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик отсутствия ответов
|
||||
*/
|
||||
void MB_Diagnostics_SlaveMessageCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveMessage < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveMessage++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик отсутствия ответов
|
||||
*/
|
||||
void MB_Diagnostics_SlaveNoResponseCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveNoResponse < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveNoResponse++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик NAK ответов
|
||||
*/
|
||||
void MB_Diagnostics_SlaveNAKCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveNAK < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveNAK++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик занятости устройства
|
||||
*/
|
||||
void MB_Diagnostics_SlaveBusyCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveBusy < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveBusy++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получение текущего режима устройства
|
||||
* @return Текущий режим работы устройства
|
||||
*/
|
||||
MB_DeviceModeTypeDef MB_GetDeviceMode(void)
|
||||
{
|
||||
return MB_DIAG.DeviceMode;
|
||||
}
|
||||
|
||||
#else //MODBUS_ENABLE_DIAGNOSTICS
|
||||
|
||||
void MB_DiagnosticsInit(void) {}
|
||||
int MB_GetDiagnosticResponse(RS_MsgTypeDef *modbus_msg, uint16_t *data) {return 0;}
|
||||
int MB_Diagnostics_WriteBit(int bit_num, int bit_state) {return 0;}
|
||||
int MB_Diagnostics_GetBit(int bit_num) {return 0;}
|
||||
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
void MB_Diagnostics_BusMessageCnt(void) {}
|
||||
void MB_Diagnostics_CommunicationErrorCnt(void) {}
|
||||
void MB_Diagnostics_ExceptionErrorCnt(void) {}
|
||||
void MB_Diagnostics_CharacterOverrunCnt(void) {}
|
||||
void MB_Diagnostics_SlaveMessageCnt(void) {}
|
||||
void MB_Diagnostics_SlaveNoResponseCnt(void) {}
|
||||
void MB_Diagnostics_SlaveNAKCnt(void) {}
|
||||
void MB_Diagnostics_SlaveBusyCnt(void) {}
|
||||
MB_DeviceModeTypeDef MB_GetDeviceMode(void) {return MODBUS_NORMAL_MODE;}
|
||||
|
||||
#endif
|
||||
@@ -21,13 +21,16 @@
|
||||
#include "modbus_inputregs.h"
|
||||
|
||||
|
||||
#ifdef MODBUS_ENABLE_HOLDINGS
|
||||
|
||||
|
||||
/**
|
||||
* @brief Proccess command Read Holding Registers (03 - 0x03).
|
||||
* @brief Обработать функцию Read Holding Registers (03 - 0x03).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Read Holding Registers.
|
||||
*/
|
||||
uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
// get origin address for data
|
||||
@@ -50,12 +53,12 @@ uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Proccess command Write Single Register (06 - 0x06).
|
||||
* @brief Обработать функцию Write Single Register (06 - 0x06).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Single Register.
|
||||
*/
|
||||
uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
// get origin address for data
|
||||
uint16_t *pHoldRegs;
|
||||
@@ -69,12 +72,12 @@ uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Proccess command Write Multiple Registers (16 - 0x10).
|
||||
* @brief Обработать функцию Write Multiple Registers (16 - 0x10).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Multiple Registers.
|
||||
*/
|
||||
uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
|
||||
@@ -95,3 +98,12 @@ uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#else //MODBUS_ENABLE_HOLDINGS
|
||||
|
||||
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
|
||||
#endif
|
||||
@@ -9,17 +9,18 @@
|
||||
Копирование данных из структур устройства в буфер ответа
|
||||
- Поддержка знаковых и беззнаковых значений
|
||||
******************************************************************************/
|
||||
|
||||
#include "modbus_inputregs.h"
|
||||
|
||||
|
||||
#ifdef MODBUS_ENABLE_INPUTS
|
||||
|
||||
/**
|
||||
* @brief Proccess command Read Input Registers (04 - 0x04).
|
||||
* @brief Обработать функцию Read Input Registers (04 - 0x04).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Read Input Registers.
|
||||
*/
|
||||
uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
// get origin address for data
|
||||
@@ -43,3 +44,9 @@ uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else //MODBUS_ENABLE_INPUTS
|
||||
|
||||
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||
|
||||
#endif
|
||||
519
Modbus/Src/modbus_master.c
Normal file
519
Modbus/Src/modbus_master.c
Normal file
@@ -0,0 +1,519 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file modbus_master.c
|
||||
* @brief Модуль для реализации мастера MODBUS.
|
||||
**************************************************************************
|
||||
* @details
|
||||
Файл содержит реализацию функций для работы Modbus в режиме мастера.
|
||||
|
||||
@section Функции и макросы
|
||||
|
||||
- MB_Master_Collect_Message() — Сбор сообщения в режиме мастера
|
||||
- MB_Master_Parse_Message() — Парс сообщения в режиме мастера
|
||||
******************************************************************************/
|
||||
#include "modbus.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_MASTER
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить значение регистра из ответа по его адресу
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param reg_addr Адрес регистра, значение которого нужно получить
|
||||
* @param reg_value Указатель для значения регистра
|
||||
* @return 1 - успех, 0 - ошибка или reg_addr вне диапазона запроса
|
||||
*/
|
||||
int MB_GetRegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value)
|
||||
{
|
||||
if(modbus_msg == NULL || reg_value == NULL)
|
||||
return 0;
|
||||
|
||||
// Проверяем что reg_addr в пределах запрошенного диапазона
|
||||
if(reg_addr < modbus_msg->Addr || reg_addr >= modbus_msg->Addr + modbus_msg->Qnt)
|
||||
return 0;
|
||||
|
||||
// Вычисляем индекс регистра в полученных данных
|
||||
uint16_t reg_index = reg_addr - modbus_msg->Addr;
|
||||
|
||||
// Проверяем что регистр существует в данных
|
||||
if(reg_index >= modbus_msg->ByteCnt / 2)
|
||||
return 0;
|
||||
|
||||
// Получаем значение регистра
|
||||
*reg_value = modbus_msg->DATA[reg_index];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
|
||||
// Master mode - calculating response size from slave
|
||||
if (modbus_msg->Func_Code & ERR_VALUES_START)
|
||||
{
|
||||
// Error response: [Addr][Func|0x80][ExceptCode][CRC]
|
||||
mb_func_size = -1; // Only Exception Code
|
||||
}
|
||||
else if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||
{
|
||||
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||
mb_func_size = 1;
|
||||
}
|
||||
else if (modbus_msg->Func_Code == MB_R_DEVICE_INFO)
|
||||
{
|
||||
// Device identifications: variable size, need to read first to determine
|
||||
mb_func_size = 0; // Will be determined after reading header
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (modbus_msg->Func_Code & ~ERR_VALUES_START)
|
||||
{
|
||||
case 0x01: // Read Coils
|
||||
case 0x02: // Read Discrete Inputs
|
||||
case 0x03: // Read Holding Registers
|
||||
case 0x04: // Read Input Registers
|
||||
// Response: [ByteCount][Data...]
|
||||
mb_func_size = modbus_msg->ByteCnt + 2; // ByteCount + variable data
|
||||
break;
|
||||
|
||||
case 0x05: // Write Single Coil
|
||||
case 0x06: // Write Single Register
|
||||
// Echo response: [Addr][Value][CRC]
|
||||
mb_func_size = 4; // Address(2) + Value(2)
|
||||
break;
|
||||
|
||||
case 0x0F: // Write Multiple Coils
|
||||
case 0x10: // Write Multiple Registers
|
||||
// Echo response: [Addr][Qty][CRC]
|
||||
mb_func_size = 4; // Address(2) + Quantity(2)
|
||||
break;
|
||||
|
||||
default:
|
||||
mb_func_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
|
||||
return mb_func_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения буфера.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
|
||||
//------INFO ABOUT DATA/MESSAGE------
|
||||
//-----------[first bytes]-----------
|
||||
// set ID of slave device
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
||||
|
||||
// set function code
|
||||
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) // device identifications request
|
||||
{
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
|
||||
}
|
||||
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||
{
|
||||
// Diagnostics: [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 // classic modbus request
|
||||
{
|
||||
// set address
|
||||
modbus_uart_buff[ind++] = modbus_msg->Addr >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->Addr & 0xFF;
|
||||
|
||||
// set quantity
|
||||
modbus_uart_buff[ind++] = modbus_msg->Qnt >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->Qnt & 0xFF;
|
||||
|
||||
// for write multiple functions
|
||||
if((modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10))
|
||||
{
|
||||
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
||||
|
||||
// write data bytes
|
||||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||
{
|
||||
modbus_uart_buff[ind++] = tmp_data_addr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ind < 0)
|
||||
return RS_COLLECT_MSG_ERR;
|
||||
|
||||
//---------------CRC----------------
|
||||
//---------[last 2 bytes]----------
|
||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||
modbus_msg->MB_CRC = CRC_VALUE;
|
||||
modbus_uart_buff[ind++] = CRC_VALUE & 0xFF;
|
||||
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
||||
|
||||
hmodbus->RS_Message_Size = ind;
|
||||
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Парс сообщения в режиме мастер (фрейм слейва из uart -> msg).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения структуры.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
int expected_size = 0;
|
||||
|
||||
// get ID of slave device
|
||||
modbus_msg->MbAddr = modbus_uart_buff[ind++];
|
||||
|
||||
// get function code (check if error response)
|
||||
modbus_msg->Func_Code = modbus_uart_buff[ind++];
|
||||
|
||||
if(modbus_msg->Func_Code & ERR_VALUES_START) // error response
|
||||
{
|
||||
modbus_msg->Except_Code = modbus_uart_buff[ind++];
|
||||
}
|
||||
else if(modbus_msg->Func_Code < ERR_VALUES_START) // normal response
|
||||
{
|
||||
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications response
|
||||
{
|
||||
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 = modbus_uart_buff[ind++];
|
||||
|
||||
modbus_msg->ByteCnt = 0;
|
||||
|
||||
// Парсинг объектов идентификации устройства
|
||||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
||||
int data_index = 0;
|
||||
|
||||
for(int obj = 0; obj < modbus_msg->DevId.NumbOfObj; obj++)
|
||||
{
|
||||
// Читаем ID объекта
|
||||
uint8_t object_id = modbus_uart_buff[ind++];
|
||||
tmp_data_addr[data_index++] = object_id;
|
||||
|
||||
// Читаем длину объекта
|
||||
uint8_t object_length = modbus_uart_buff[ind++];
|
||||
tmp_data_addr[data_index++] = object_length;
|
||||
|
||||
// Читаем данные объекта
|
||||
for(int i = 0; i < object_length; i++)
|
||||
{
|
||||
tmp_data_addr[data_index++] = modbus_uart_buff[ind++];
|
||||
}
|
||||
|
||||
modbus_msg->ByteCnt += (2 + object_length); // ID + длина + данные
|
||||
}
|
||||
}
|
||||
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||
{
|
||||
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||
modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->DATA[0] |= modbus_uart_buff[ind++];
|
||||
modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->DATA[1] |= modbus_uart_buff[ind++];
|
||||
}
|
||||
else // classic modbus response
|
||||
{
|
||||
// get byte count for read functions
|
||||
if((modbus_msg->Func_Code == 0x01) || (modbus_msg->Func_Code == 0x02) ||
|
||||
(modbus_msg->Func_Code == 0x03) || (modbus_msg->Func_Code == 0x04))
|
||||
{
|
||||
modbus_msg->ByteCnt = modbus_uart_buff[ind++];
|
||||
|
||||
// read data bytes
|
||||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||
{
|
||||
if(i % 2 == 0) // HI byte
|
||||
tmp_data_addr[i/2] = (uint16_t)modbus_uart_buff[ind++] << 8;
|
||||
else // LO byte
|
||||
tmp_data_addr[i/2] |= modbus_uart_buff[ind++];
|
||||
}
|
||||
}
|
||||
// for write functions - echo address and quantity
|
||||
else if((modbus_msg->Func_Code == 0x05) || (modbus_msg->Func_Code == 0x06) ||
|
||||
(modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10))
|
||||
{
|
||||
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
||||
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------CRC----------------
|
||||
//----------[last 2 bytes]----------
|
||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||
modbus_msg->MB_CRC = modbus_uart_buff[ind++];
|
||||
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8;
|
||||
|
||||
if(modbus_msg->MB_CRC != CRC_VALUE)
|
||||
{
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
return RS_PARSE_MSG_ERR;
|
||||
}
|
||||
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Сформировать запрос на чтение коилов */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на чтение дискретных регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_DISC_IN, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на чтение холдинг регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на чтение инпут регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_IN_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись одного коила */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_W_COIL, {0}, coil_addr, (value ? 0xFF00 : 0x0000), 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись одного регистра */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_W_HOLD_REG, {0}, reg_addr, value, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись нескольких регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_W_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
|
||||
// Calculate byte count and prepare data
|
||||
uint8_t byte_count = (quantity + 7) / 8;
|
||||
msg.ByteCnt = byte_count;
|
||||
|
||||
// Copy coil data to message DATA array
|
||||
for(int i = 0; i < byte_count; i++) {
|
||||
if(i < DATA_SIZE) {
|
||||
msg.DATA[i] = coils_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись нескольких коилов */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_W_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
|
||||
msg.ByteCnt = quantity * 2; // Each register is 2 bytes
|
||||
|
||||
// Copy register data to message DATA array
|
||||
for(int i = 0; i < quantity && i < DATA_SIZE; i++) {
|
||||
msg.DATA[i] = regs_data[i];
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_DIAGNOSTIC, {0}, 0, 0, 0, {sub_function, data}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0000, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0001, data);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0002, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0004, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000A, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000B, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000C, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000D, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000E, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000F, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0010, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0011, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0012, 0x0000);
|
||||
}
|
||||
|
||||
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x01, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x02, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x03, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x04, object_id, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
RS_MsgTypeDef msg_dummy = {0};
|
||||
|
||||
int MB_GetRegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value) {return 0;}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data) {return msg_dummy;}
|
||||
|
||||
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||
|
||||
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr) {return msg_dummy;}
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id) {return msg_dummy;}
|
||||
|
||||
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
437
Modbus/Src/modbus_slave.c
Normal file
437
Modbus/Src/modbus_slave.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file modbus_slave.c
|
||||
* @brief Модуль для реализации слейв MODBUS.
|
||||
**************************************************************************
|
||||
* @details
|
||||
Файл содержит реализацию функций для работы Modbus в режиме слейва.
|
||||
|
||||
@section Функции и макросы
|
||||
|
||||
- MB_Slave_Response() — Ответ на запрос
|
||||
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
||||
- MB_Slave_Parse_Message() — Парс сообщения в режиме слейва.
|
||||
******************************************************************************/
|
||||
#include "modbus.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_SLAVE
|
||||
/**
|
||||
* @brief Ответ на сообщение в режиме слейва.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о результате ответа на комманду.
|
||||
*/
|
||||
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_Process_Read_Coils(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
// Read Hodling Registers
|
||||
case MB_R_HOLD_REGS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
|
||||
break;
|
||||
case MB_R_IN_REGS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
|
||||
// Write Single Coils
|
||||
case MB_W_COIL:
|
||||
hmodbus->f.MessageHandled = MB_Process_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_Process_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_Process_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_Process_Read_Device_Identifications(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
// Добавить в switch-case после других case:
|
||||
case MB_R_DIAGNOSTIC:
|
||||
hmodbus->f.MessageHandled = MB_Process_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 в режиме слейв (фрейм слейва из msg -> uart).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения буфера.
|
||||
*/
|
||||
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 identifications 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 Парс сообщения в режиме слейв (фрейм мастера из uart -> msg).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения структуры.
|
||||
* @details Заполнение структуры сообщения из буффера UART.
|
||||
*/
|
||||
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 identifications 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;
|
||||
}
|
||||
|
||||
#else // MODBUS_ENABLE_SLAVE
|
||||
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) {return RS_ERR;}
|
||||
RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||
RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||
#endif
|
||||
@@ -23,6 +23,7 @@
|
||||
- RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler()
|
||||
******************************************************************************/
|
||||
#include "rs_message.h"
|
||||
#include "modbus_diag.h"
|
||||
|
||||
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
|
||||
|
||||
@@ -34,7 +35,7 @@ extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim);
|
||||
//-------------------------------------------------------------------
|
||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||
/**
|
||||
* @brief Start receive IT.
|
||||
* @brief Начать прием по прерываниям.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации приема.
|
||||
@@ -60,7 +61,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
|
||||
// start receiving
|
||||
__HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE);
|
||||
uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte,
|
||||
uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte,
|
||||
// then in Callback restart receive for rest bytes
|
||||
|
||||
// if receive isnt started - abort RS
|
||||
@@ -82,7 +83,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start transmit IT.
|
||||
* @brief Начать передачу по прерываниям.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
||||
@@ -111,7 +112,6 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
|
||||
//----------INITIALIZE TRANSMIT-------------
|
||||
RS_EnableTransmit();
|
||||
// for(int i = 0; i < hRS->sRS_Timeout; i++);
|
||||
|
||||
RS_Set_Busy(hRS); // set RS busy
|
||||
RS_Set_TX_Flags(hRS); // initialize flags for transmit IT
|
||||
@@ -145,13 +145,13 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize UART and handle RS stucture.
|
||||
* @brief Инициалазация структуры @ref RS_HandleTypeDef.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param suart Указатель на структуру с настройками UART.
|
||||
* @param stim Указатель на структуру с настройками таймера.
|
||||
* @param pRS_BufferPtr Указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации.
|
||||
* @note Инициализация перефирии и структуры для приема-передачи по RS.
|
||||
* @details Инициализация перефирии и структуры для приема-передачи по RS.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr)
|
||||
{
|
||||
@@ -166,9 +166,6 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
|
||||
|
||||
hRS->htim = htim;
|
||||
|
||||
if (hRS->sRS_RX_Size_Mode == NULL)
|
||||
return RS_ERR;
|
||||
|
||||
// check that buffer is defined
|
||||
if (hRS->pBufferPtr == NULL)
|
||||
{
|
||||
@@ -182,7 +179,7 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
|
||||
|
||||
|
||||
/**
|
||||
* @brief Abort RS/UART.
|
||||
* @brief Отменить прием/передачу RS/UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param AbortMode Выбор, что надо отменить.
|
||||
- ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX,
|
||||
@@ -190,20 +187,14 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
|
||||
- ABORT_RX_TX: Отмена приема и передачи по ЮАРТ,
|
||||
- ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры.
|
||||
* @return RS_RES Статус о состоянии RS после аборта.
|
||||
* @note Отмена работы UART в целом или отмена приема/передачи RS.
|
||||
Также очищается хендл hRS.
|
||||
* @details Отмена работы UART в целом или отмена приема/передачи RS.
|
||||
Также очищается хендл hRS.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode)
|
||||
{
|
||||
HAL_StatusTypeDef uart_res = 0;
|
||||
|
||||
if(hRS->htim)
|
||||
{
|
||||
if(hRS->sRS_Timeout) // if timeout setted
|
||||
HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout
|
||||
hRS->htim->Instance->CNT = 0;
|
||||
__HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE);
|
||||
}
|
||||
RS_Timeout_Stop(hRS);
|
||||
|
||||
if((AbortMode&ABORT_RS) == 0x00)
|
||||
{
|
||||
@@ -237,11 +228,11 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode)
|
||||
//-------------------------------------------------------------------
|
||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||
/**
|
||||
* @brief Handle for starting receive.
|
||||
* @brief Обработчик для начала приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации приема или окончания общения.
|
||||
* @note Определяет начинать прием команды/ответа или нет.
|
||||
* @details Определяет начинать прием команды/ответа или нет.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
@@ -249,9 +240,15 @@ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *R
|
||||
|
||||
switch(hRS->sRS_Mode)
|
||||
{
|
||||
case RS_SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting
|
||||
RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again
|
||||
case RS_SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request)
|
||||
// В режиме мастер
|
||||
case RS_MASTER_REQUEST:
|
||||
RS_Timeout_Start(hRS); // сразу запускаем таймаут и начинаем прием
|
||||
// В режиме слейв
|
||||
case RS_SLAVE_ALWAYS_WAIT:
|
||||
RS_RES = RS_Receive_IT(hRS, RS_msg); // Просто запускаем фоновый прием
|
||||
break;
|
||||
|
||||
case RS_RESERVED:
|
||||
RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy)
|
||||
}
|
||||
|
||||
@@ -263,11 +260,11 @@ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *R
|
||||
return RS_RES;
|
||||
}
|
||||
/**
|
||||
* @brief Handle for starting transmit.
|
||||
* @brief Обработчик для начала передачи.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
||||
* @note Определяет отвечать ли на команду или нет.
|
||||
* @details Определяет отвечать ли на команду или нет.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
@@ -276,13 +273,14 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *
|
||||
switch(hRS->sRS_Mode)
|
||||
{
|
||||
case RS_SLAVE_ALWAYS_WAIT: // in slave mode always response
|
||||
case RS_SLAVE_TIMEOUT_WAIT: // transmit response
|
||||
case RS_RESERVED: // transmit response
|
||||
case RS_MASTER_REQUEST: // transmit response
|
||||
RS_RES = RS_Transmit_IT(hRS, RS_msg); break;
|
||||
}
|
||||
|
||||
if(RS_RES != RS_OK)
|
||||
{
|
||||
if(hRS->sRS_Mode < RS_MASTER_START)
|
||||
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
RS_Handle_Receive_Start(hRS, RS_msg);
|
||||
}
|
||||
@@ -294,10 +292,10 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART TX Callback: define behaviour after transmiting message.
|
||||
* @brief UART TX Callback: коллбек после окончания передачи.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус о состоянии RS после обработки приема.
|
||||
* @note Определяет поведение RS после передачи сообщения.
|
||||
* @details Определяет поведение RS после передачи сообщения.
|
||||
*/
|
||||
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
@@ -306,24 +304,18 @@ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
|
||||
|
||||
//--------------ENDING TRANSMITTING-------------
|
||||
RS_Set_TX_End(hRS);
|
||||
RS_EnableReceive();
|
||||
// for(int i = 0; i < hRS->sRS_Timeout; i++);
|
||||
|
||||
//-----------START RECEIVING or END RS----------
|
||||
RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
|
||||
// if(RS_RES != RS_OK)
|
||||
// {
|
||||
// __NOP();
|
||||
// }
|
||||
return RS_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handler for UART.
|
||||
* @brief Обработчик прерывания UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @note Обрабатывает ошибки если есть и вызывает RS Коллбеки.
|
||||
* Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler().
|
||||
* @details Обрабатывает ошибки если есть и вызывает RS Коллбеки.
|
||||
* Добавить вызов этой функции в UARTx_IRQHandler() ВМЕСТО HAL_UART_IRQHandler().
|
||||
*/
|
||||
void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
@@ -331,13 +323,14 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//-------------CHECK IDLE FLAG FIRST-------------
|
||||
//-------------CHECK IDLE FLAG FIRST-------------
|
||||
/* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */
|
||||
if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE))
|
||||
{
|
||||
__HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE
|
||||
//-------------STANDARD UART HANDLING-------------
|
||||
HAL_UART_IRQHandler(hRS->huart);
|
||||
hRS->f.RX_Continue = 0;
|
||||
|
||||
// Если прием активен и мы получили IDLE - это конец фрейма
|
||||
if(RS_Is_RX_Busy(hRS) && hRS->f.RX_Ongoing)
|
||||
@@ -356,29 +349,23 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
|
||||
// Парсим наше сообщение
|
||||
RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr);
|
||||
|
||||
// Проверяем адрес Modbus перед обработкой
|
||||
if(hRS->pMessagePtr->MbAddr != hRS->ID)
|
||||
|
||||
// Если сообещине принято корректно
|
||||
if(parse_res == RS_OK)
|
||||
{
|
||||
// Чужое сообщение - игнорируем и начинаем новый прием
|
||||
RS_Abort(hRS, ABORT_RX);
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Если сообещине принято корректно - отвечаем на него
|
||||
if(parse_res != RS_SKIP)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
// Останавливаем таймаут
|
||||
if(hRS->sRS_Timeout)
|
||||
HAL_TIM_Base_Stop_IT(hRS->htim);
|
||||
}
|
||||
RS_Timeout_Stop(hRS);
|
||||
|
||||
hRS->lastPacketTick = uwTick;
|
||||
RS_Response(hRS, hRS->pMessagePtr);
|
||||
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||
RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос
|
||||
else
|
||||
{
|
||||
if(hRS->pCallback)
|
||||
{
|
||||
hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ
|
||||
RS_Set_Free(hRS); // освобожднаем RS
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -399,19 +386,13 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
/* IF NO ERROR OCCURS */
|
||||
if(hRS->huart->ErrorCode == 0)
|
||||
{
|
||||
|
||||
if(hRS->htim)
|
||||
|
||||
// if first byte is received and receive is active
|
||||
if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS))
|
||||
{
|
||||
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||
/* Start timeout при получении первого байта */
|
||||
if(hRS->sRS_Timeout) // if timeout setted
|
||||
if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active
|
||||
{
|
||||
hRS->htim->Instance->ARR = hRS->sRS_Timeout;
|
||||
HAL_TIM_Base_Start_IT(hRS->htim);
|
||||
RS_Set_RX_Active_Flags(hRS);
|
||||
}
|
||||
RS_Timeout_Start(hRS);
|
||||
}
|
||||
RS_Timeout_Update(hRS);
|
||||
|
||||
/* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */
|
||||
|
||||
@@ -425,6 +406,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
//----------------ERRORS HANDLER----------------
|
||||
else
|
||||
{
|
||||
if (hRS->huart->ErrorCode & HAL_UART_ERROR_ORE)
|
||||
{
|
||||
MB_Diagnostics_CharacterOverrunCnt(); // <-- Обнаружено переполнение
|
||||
}
|
||||
//TrackerCnt_Err(hRS->rs_err);
|
||||
/* de-init uart transfer */
|
||||
RS_Abort(hRS, ABORT_RS);
|
||||
@@ -436,10 +421,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handler for TIM.
|
||||
* @brief Обработчик прерывания TIM.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @note Попадание сюда = таймаут и перезапуск RS приема
|
||||
* Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler().
|
||||
* @details Попадание сюда = таймаут и перезапуск RS приема
|
||||
* Добавить вызов этой функции в TIMx_IRQHandler() ВМЕСТО HAL_TIM_IRQHandler().
|
||||
*/
|
||||
void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
@@ -449,13 +434,73 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
||||
}
|
||||
HAL_TIM_IRQHandler(hRS->htim);
|
||||
|
||||
RS_Abort(hRS, ABORT_RS);
|
||||
RS_Abort(hRS, ABORT_RS);
|
||||
|
||||
if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
if(hRS->sRS_Mode == RS_MASTER_REQUEST) {
|
||||
// Мастер: таймаут ответа -> освобождаем для нового запроса
|
||||
RS_Set_Free(hRS);
|
||||
} else {
|
||||
// Слейв: перезапускаем прием
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Запуск таймаута приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус операции.
|
||||
* @details Запускает таймер для отсчета времени ожидания следующего байта.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||
if(hRS->sRS_Timeout) // if timeout setted
|
||||
{
|
||||
hRS->htim->Instance->ARR = hRS->sRS_Timeout;
|
||||
HAL_TIM_Base_Start_IT(hRS->htim);
|
||||
RS_Set_RX_Active_Flags(hRS);
|
||||
}
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Остановка таймаута приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус операции.
|
||||
* @details Останавливает таймер ожидания.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
// Останавливаем таймаут
|
||||
if(hRS->sRS_Timeout)
|
||||
HAL_TIM_Base_Stop_IT(hRS->htim);
|
||||
hRS->htim->Instance->CNT = 0;
|
||||
__HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE);
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Обновление (сброс) таймаута приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус операции.
|
||||
* @details Сбрасывает счетчик таймера в 0.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
@@ -468,7 +513,6 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о результате ответа на комманду.
|
||||
* @note Обработка принятой комманды и ответ на неё.
|
||||
*/
|
||||
__weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
@@ -477,12 +521,11 @@ __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Собрать сообщение в буфер UART.
|
||||
* @brief Пользовательская функция для сбора сообщения в буфер UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @param msg_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения буфера.
|
||||
* @note Заполнение буффера UART из структуры сообщения.
|
||||
*/
|
||||
__weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
||||
{
|
||||
@@ -491,12 +534,11 @@ __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Разпарсить сообщение из буфера UART.
|
||||
* @brief Пользовательская функция для парса сообщения из буфера UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @param msg_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения структуры.
|
||||
* @note Заполнение структуры сообщения из буффера UART.
|
||||
*/
|
||||
__weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user