Улучшена логика отправки сообщений и реализованы новые функции пакетной передачи
Реализована обработка разных типов сообщений (BroadCast, Discrete, Analog) в функции PROTOCAN_SEND_CORE с корректной разбивкой данных на пакеты размером до 8 байт. Добавлены новые функции для пакетной отправки данных по диапазону регистров (PROTOCAN_SEND_GENERAL_ADDRESS_SPACE) и модбас-данных (PROTOCAN_SEND_MODBUS).
This commit is contained in:
@@ -252,14 +252,20 @@ typedef struct{
|
||||
unsigned LastPulseStep; /**< Шаг последнего импульса. */
|
||||
} ProtoCanDevice_t;
|
||||
|
||||
/**
|
||||
* @brief Структура для хранения сообщения RXCAN.
|
||||
*/
|
||||
struct RXMsg {
|
||||
/**
|
||||
* @brief Структура, содержащая флаги информации.
|
||||
*/
|
||||
struct INFO {
|
||||
unsigned EXT:1;
|
||||
unsigned RTR:1;
|
||||
}info;
|
||||
ProtoCanId_t eID;
|
||||
uint16_t DLC;
|
||||
uint8_t Data[8];
|
||||
unsigned EXT : 1; /**< Бит расширенного идентификатора (EXT). */
|
||||
unsigned RTR : 1; /**< Бит запроса на передачу (RTR). */
|
||||
} info; /**< Информационные флаги сообщения. */
|
||||
ProtoCanId_t eID; /**< Идентификатор CAN-сообщения. */
|
||||
uint16_t DLC; /**< Длина данных (Data Length Code). */
|
||||
uint8_t Data[8]; /**< Массив данных (до 8 байт). */
|
||||
};
|
||||
|
||||
uint16_t AvailableCanRxMsg(void);
|
||||
|
||||
@@ -635,6 +635,107 @@ __weak PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg _rxMsg)
|
||||
return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет сообщение по CAN-шине в соответствии с типом протокола.
|
||||
* Эта функция формирует и отправляет сообщение через CAN-шину, основываясь на типе
|
||||
* переданного ID и данных. Поддерживаются типы сообщений: широковещательные, дискретные
|
||||
* и аналоговые.
|
||||
* @param id Идентификатор сообщения, содержащий тип сообщения и другую информацию.
|
||||
* @param coreData Структура данных, включающая тип, тело и данные для передачи.
|
||||
* @return PROTOCAN_StatusTypeDef Статус операции.
|
||||
* @details
|
||||
* В зависимости от типа сообщения (панель broadcast, discrete или analog),
|
||||
* формируется соответствующий пакет данных и отправляется на шину CAN.
|
||||
* Для сообщений, превышающих длину 8 байт, передача выполняется пакетами.
|
||||
* В случае ошибок при добавлении сообщения в очередь передачи, возвращается ошибка.
|
||||
*/
|
||||
PROTOCAN_StatusTypeDef PROTOCAN_SEND_CORE(const ProtoCanId_t id, const struct ProtoCanCoreData coreData)
|
||||
{
|
||||
ProtoCanId_t localId = id;
|
||||
uint8_t msgType = localId.Fields.MsgType;
|
||||
CAN_TxHeaderTypeDef TxHeader;
|
||||
TxHeader.IDE = CAN_ID_EXT;
|
||||
TxHeader.RTR = CAN_RTR_DATA;
|
||||
TxHeader.TransmitGlobalTime = DISABLE;
|
||||
uint32_t TxMailBox = 0;
|
||||
uint8_t canData[8];
|
||||
switch(id.Fields.MsgType)
|
||||
{
|
||||
case PROTOCAN_MSGTYPE_BROADCAST:
|
||||
{
|
||||
msgBodyBroadcastType body;
|
||||
body.Fields.Type = coreData.Type;
|
||||
body.Fields.Body = coreData.Body;
|
||||
localId.Fields.MsgBody = body.Body;
|
||||
TxHeader.ExtId = localId.BitAll;
|
||||
TxHeader.DLC = 0;
|
||||
if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK)
|
||||
{
|
||||
return PROTOCAN_ERROR;
|
||||
}
|
||||
}
|
||||
case PROTOCAN_MSGTYPE_DISCRETE:
|
||||
{
|
||||
msgBodyDiscreteType body;
|
||||
body.Fields.Type = coreData.Type;
|
||||
uint8_t regsRemaining = coreData.DataCount;
|
||||
uint8_t currentIndex = 0;
|
||||
while(regsRemaining > 0)
|
||||
{
|
||||
uint8_t regsInPacket = (regsRemaining > 8) ? 8 : regsRemaining;
|
||||
body.Fields.Body = coreData.Body + currentIndex;
|
||||
localId.Fields.MsgBody = body.Body;
|
||||
TxHeader.ExtId = localId.BitAll;
|
||||
TxHeader.DLC = regsInPacket;
|
||||
for(int i = 0; i < regsInPacket; i++)
|
||||
{
|
||||
canData[i] = coreData.Data[coreData.DataCount - regsRemaining];
|
||||
}
|
||||
HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox);
|
||||
if(status != HAL_OK)
|
||||
{
|
||||
return (PROTOCAN_StatusTypeDef)status;
|
||||
}
|
||||
regsRemaining -= regsInPacket;
|
||||
currentIndex += regsInPacket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROTOCAN_MSGTYPE_ANALOG:
|
||||
{
|
||||
msgBodyAnalogType body;
|
||||
body.Fields.Type = coreData.Type;
|
||||
uint8_t regsRemaining = coreData.DataCount;
|
||||
uint8_t currentIndex = 0;
|
||||
while(regsRemaining > 0)
|
||||
{
|
||||
uint8_t regsInPacket = (regsRemaining > 8) ? 8 : regsRemaining;
|
||||
body.Fields.SensorID = coreData.Body + currentIndex;
|
||||
localId.Fields.MsgBody = body.Body;
|
||||
TxHeader.ExtId = localId.BitAll;
|
||||
TxHeader.DLC = regsInPacket;
|
||||
for(int i = 0; i < regsInPacket; i++)
|
||||
{
|
||||
canData[i] = coreData.Data[coreData.DataCount - regsRemaining];
|
||||
}
|
||||
HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox);
|
||||
if(status != HAL_OK)
|
||||
{
|
||||
return (PROTOCAN_StatusTypeDef)status;
|
||||
}
|
||||
regsRemaining -= regsInPacket;
|
||||
currentIndex += regsInPacket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return PROTOCAN_ERROR;
|
||||
}
|
||||
}
|
||||
return PROTOCAN_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка и ответ на запрос общего адресного пространства.
|
||||
* Формирует и передает сообщение с данными о статусе "GAS-XXXX", где XXXX — значение из сообщения _rxMsg.
|
||||
@@ -674,15 +775,12 @@ __weak PROTOCAN_StatusTypeDef ProtoCanMsgToGeneralAddressSpace(struct RXMsg _rxM
|
||||
|
||||
/**
|
||||
* @brief Отправляет произвольный диапазон регистров в пакетах по, максимум, 4 регистра за раз через CAN.
|
||||
*
|
||||
* Функция разбивает передаваемый массив регистров на пакеты по 4 или меньше и отправляет их по отдельности.
|
||||
* Для каждого пакета формируется уникальный MsgBody, равный адресу первого регистра в пакете.
|
||||
*
|
||||
* @param priority Приоритет сообщения CAN. ProtoCan_Priority_TypeDef
|
||||
* @param regStartAdr Адрес первого регистра из всего массива.
|
||||
* @param data Указатель на массив регистров для отправки.
|
||||
* @param regCount Общее количество регистров для отправки.
|
||||
*
|
||||
* @return Возвращает статус отправки: HAL_OK при успехе, или код ошибки HAL_StatusTypeDef при сбое.
|
||||
*/
|
||||
PROTOCAN_StatusTypeDef PROTOCAN_SEND_GENERAL_ADDRESS_SPACE(ProtoCanId_t id, uint16_t regStartAdr, uint16_t *data, uint8_t regCount)
|
||||
@@ -896,14 +994,21 @@ __weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет данные Modbus через CAN-шину в соответствии с типом сообщения.
|
||||
* Эта функция формирует и отправляет Modbus-данные по CAN-шине, поддерживая
|
||||
* различные типы сообщений: Coil, Discrete, Holding Register и Input Register.
|
||||
* Для сообщений, превышающих 4 регистров, данные отправляются пакетами.
|
||||
* @param id Идентификатор сообщения, содержащий тип сообщения и другую информацию.
|
||||
* @param modbusData Структура с данными Modbus: адрес, количество регистров и сами данные.
|
||||
* @return PROTOCAN_StatusTypeDef Статус операции.
|
||||
* @details
|
||||
* В зависимости от типа Modbus (coil/discrete или holding/input), формируется
|
||||
* соответствующий CAN-пакет. Для coil/discrete отправляется один пакет, для holding/input —
|
||||
* несколько, по 4 регистра в пакете. В случае ошибок при добавлении сообщения API HAL возвращается ошибка.
|
||||
*/
|
||||
int PROTOCAN_SEND_MODBUS(const ProtoCanId_t* id, const struct ProtoCanModbusData* modbusData)
|
||||
PROTOCAN_StatusTypeDef PROTOCAN_SEND_MODBUS(const ProtoCanId_t id, const struct ProtoCanModbusData modbusData)
|
||||
{
|
||||
if (!id || !modbusData)
|
||||
{
|
||||
return PROTOCAN_ERROR;
|
||||
}
|
||||
ProtoCanId_t localId = *id;
|
||||
ProtoCanId_t localId = id;
|
||||
uint8_t msgType = localId.Fields.MsgType;
|
||||
// Структура для отправки
|
||||
CAN_TxHeaderTypeDef TxHeader;
|
||||
@@ -913,20 +1018,20 @@ int PROTOCAN_SEND_MODBUS(const ProtoCanId_t* id, const struct ProtoCanModbusData
|
||||
{
|
||||
// Формируем body
|
||||
msgBodyModbusType body;
|
||||
body.Fields.StrAdr = modbusData->StrAdr;
|
||||
body.Fields.RegCount = modbusData->RegCount;
|
||||
body.Fields.StrAdr = modbusData.StrAdr;
|
||||
body.Fields.RegCount = modbusData.RegCount;
|
||||
// Устанавливаем коллизию ExtId с body.Body
|
||||
localId.Fields.MsgBody = (body.Body & 0xFFFF);
|
||||
// Обновляем ExtId
|
||||
TxHeader.ExtId = localId.BitAll;
|
||||
// Остальные настройки
|
||||
TxHeader.IDE = CAN_ID_EXT; // Предположим, что используете расширенные ID
|
||||
TxHeader.IDE = CAN_ID_EXT;
|
||||
TxHeader.RTR = CAN_RTR_DATA;
|
||||
TxHeader.TransmitGlobalTime = DISABLE;
|
||||
TxHeader.DLC = modbusData->RegCount % 8 + 1;
|
||||
TxHeader.DLC = modbusData.RegCount % 8 + 1;
|
||||
// Формируем CAN данные
|
||||
canData[0] = (*modbusData->Data) & 0xFF;
|
||||
canData[1] = (*modbusData->Data >> 8) & 0xFF;
|
||||
canData[0] = LowByteOfWord(modbusData.Data[0]);
|
||||
canData[1] = HighByteOfWord(modbusData.Data[0]);
|
||||
if (HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK)
|
||||
{
|
||||
return PROTOCAN_ERROR;
|
||||
@@ -934,10 +1039,10 @@ int PROTOCAN_SEND_MODBUS(const ProtoCanId_t* id, const struct ProtoCanModbusData
|
||||
}
|
||||
else if(msgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || msgType == PROTOCAN_MSGTYPE_MODBUS_INPUT)
|
||||
{
|
||||
uint16_t* dataPtr = modbusData->Data;
|
||||
unsigned totalRegs = modbusData->RegCount;
|
||||
uint16_t* dataPtr = modbusData.Data;
|
||||
unsigned totalRegs = modbusData.RegCount;
|
||||
unsigned regsProcessed = 0;
|
||||
unsigned startAddress = modbusData->StrAdr;
|
||||
unsigned startAddress = modbusData.StrAdr;
|
||||
while (regsProcessed < totalRegs)
|
||||
{
|
||||
uint8_t regsInPacket = (totalRegs - regsProcessed) > 4 ? 4 : (totalRegs - regsProcessed);
|
||||
@@ -1001,6 +1106,40 @@ __weak PROTOCAN_StatusTypeDef CanRequestError(struct RXMsg _rxMsg)
|
||||
return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет сообщение об ошибке по CAN-шине.
|
||||
* Эта функция формирует и отправляет сообщение об ошибке с кодом и информацией,
|
||||
* объединёнными в поле MsgBody идентификатора сообщения, и передаёт его через CAN.
|
||||
* @param id Идентификатор сообщения, содержащий базовую информацию.
|
||||
* @param errorData Структура с данными ошибки: код и дополнительная информация.
|
||||
* @return PROTOCAN_StatusTypeDef Статус операции.
|
||||
* @details
|
||||
* В качестве данных передаётся 2 байта: старшие биты — информация об ошибке, младшие — код ошибки.
|
||||
* Размер данных в CANFrames устанавливается нулевым, так как все данные инкапсулированы в MsgBody.
|
||||
*/
|
||||
PROTOCAN_StatusTypeDef PROTOCAN_SEND_ERROR(const ProtoCanId_t id, const struct ProtoCanErrorData errorData)
|
||||
{
|
||||
ProtoCanId_t localId = id;
|
||||
uint8_t msgType = localId.Fields.MsgType;
|
||||
// Структура для отправки
|
||||
CAN_TxHeaderTypeDef TxHeader;
|
||||
uint32_t TxMailBox = 0;
|
||||
uint8_t canData[8];
|
||||
localId.Fields.MsgBody = ((errorData.Info << 8) | errorData.Code);
|
||||
// Обновляем ExtId
|
||||
TxHeader.ExtId = localId.BitAll;
|
||||
// Остальные настройки
|
||||
TxHeader.IDE = CAN_ID_EXT;
|
||||
TxHeader.RTR = CAN_RTR_DATA;
|
||||
TxHeader.TransmitGlobalTime = DISABLE;
|
||||
TxHeader.DLC = 0;
|
||||
if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK)
|
||||
{
|
||||
return PROTOCAN_ERROR;
|
||||
}
|
||||
return PROTOCAN_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Записывает полученное сообщение CAN в буфер rxMsg.
|
||||
* Копирует параметры расширенного ID, типы, длину данных и сам данные в указанный элемент буфера.
|
||||
@@ -1183,32 +1322,22 @@ void PROTOCAN_FILTERS()
|
||||
|
||||
/**
|
||||
* @brief Отправляет CAN-сообщение в зависимости от типа сообщения.
|
||||
*
|
||||
* Эта функция анализирует тип сообщения в идентификаторе и вызывает
|
||||
* соответствующую функцию отправки. В текущей реализации поддерживается только
|
||||
* тип PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE.
|
||||
*
|
||||
* @param id Идентификатор CAN-сообщения, содержащий информацию о типе.
|
||||
* @param data Структура с данными, которые необходимо отправить. Зависит от типа сообщения.
|
||||
*
|
||||
* @return Статус выполнения операции:
|
||||
* - PROTOCAN_OK при успешной отправке,
|
||||
* - PROTOCAN_ERROR, если тип сообщения не поддерживается или произошла ошибка.
|
||||
* @return Статус выполнения операции.
|
||||
*/
|
||||
PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data)
|
||||
{
|
||||
switch(id.Fields.MsgType)
|
||||
{
|
||||
case PROTOCAN_MSGTYPE_BROADCAST:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case PROTOCAN_MSGTYPE_DISCRETE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case PROTOCAN_MSGTYPE_ANALOG:
|
||||
{
|
||||
return PROTOCAN_SEND_CORE(id, data.CoreData);
|
||||
break;
|
||||
}
|
||||
case PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE:
|
||||
@@ -1227,10 +1356,12 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data)
|
||||
case PROTOCAN_MSGTYPE_MODBUS_HOLDING:
|
||||
case PROTOCAN_MSGTYPE_MODBUS_INPUT:
|
||||
{
|
||||
return PROTOCAN_SEND_MODBUS(id, data.ModbusData);
|
||||
break;
|
||||
}
|
||||
case PROTOCAN_MSGTYPE_ERROR:
|
||||
{
|
||||
return PROTOCAN_SEND_ERROR(id, data.ErrorData);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user