release 0.2
Добавлен модуль диагностически модбас (функция 0x08) + мелкие кореркции
This commit is contained in:
181
Src/modbus.c
181
Src/modbus.c
@@ -9,8 +9,9 @@
|
||||
@section Функции и макросы
|
||||
|
||||
### Инициализация:
|
||||
- MODBUS_SetupHardware() — Инициализация модуля Modbus.
|
||||
- MODBUS_FirstInit() — Инициализация модуля Modbus.
|
||||
- MODBUS_Config() — Инициализация модуля Modbus.
|
||||
- MODBUS_SlaveStart() — Запуск Modbus как Slave.
|
||||
|
||||
### Функции для Modbus
|
||||
- MB_Slave_Response()
|
||||
@@ -22,45 +23,50 @@
|
||||
### Функции для работы с 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
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------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();
|
||||
MB_DiagnosticsInit();
|
||||
//-----------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;
|
||||
hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst;
|
||||
|
||||
// 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,11 +75,15 @@ 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;
|
||||
}
|
||||
if((ID < 1) || (ID > 247))
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
//-----------SETUP MODBUS-------------
|
||||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||||
@@ -84,30 +94,45 @@ void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint
|
||||
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_START)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------INTERNAL------------------------------
|
||||
|
||||
/**
|
||||
* @brief Ответ на сообщение в режиме слейва.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
@@ -121,12 +146,15 @@ static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
|
||||
hmodbus->f.EchoResponse = 0;
|
||||
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
|
||||
|
||||
if(hmodbus->ID == 0)
|
||||
MB_Diagnostics_BusMessageCnt();
|
||||
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0)
|
||||
{
|
||||
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
|
||||
hmodbus->RS_STATUS = RS_SKIP;
|
||||
return MB_RES;
|
||||
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)
|
||||
@@ -192,12 +220,30 @@ static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
|
||||
hmodbus->f.MessageHandled = MB_Proccess_Read_Device_Identification(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
// Добавить в switch-case после других case:
|
||||
case MB_R_DIAGNOSTIC:
|
||||
hmodbus->f.MessageHandled = MB_Proccess_Diagnostics(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
/* unknown func code */
|
||||
default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||
default:
|
||||
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||
MB_Diagnostics_SlaveNAKCnt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Проверяем режим устройства - если 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;
|
||||
}
|
||||
@@ -282,6 +328,14 @@ static RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_M
|
||||
}
|
||||
|
||||
}
|
||||
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
|
||||
@@ -344,24 +398,23 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
|
||||
RS_StatusTypeDef MB_RES = 0;
|
||||
int mb_func_size = 0;
|
||||
|
||||
if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F)
|
||||
if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||
{
|
||||
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)
|
||||
}
|
||||
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;
|
||||
@@ -381,20 +434,25 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
|
||||
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;
|
||||
return RS_SKIP;
|
||||
ind++;
|
||||
}
|
||||
else
|
||||
{
|
||||
modbus_msg->MbAddr = modbus_uart_buff[ind++];
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -406,6 +464,18 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
|
||||
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
|
||||
@@ -422,6 +492,20 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
|
||||
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)
|
||||
@@ -431,6 +515,7 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
|
||||
{
|
||||
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;
|
||||
@@ -456,6 +541,7 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
|
||||
// compare crc
|
||||
if (modbus_msg->MB_CRC != CRC_VALUE)
|
||||
{
|
||||
MB_Diagnostics_CommunicationErrorCnt();
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||||
}
|
||||
@@ -468,17 +554,6 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
|
||||
// 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user