|
- #include "modbus_rtu_slave.h"
- #include "ucos_ii.h"
- #include <string.h>
-
- #define MODBUS_RTU_ADU_SIZE_MAX (256U)//Modbus RTU 最大 ADU 长度,单位为字节
-
-
- #define MODBUS_RTU_FRAME_GAP_MS (2U)
-
- #define MODBUS_BROADCAST_ADDRESS (0U)//广播地址
-
- #define MODBUS_EX_ILLEGAL_FUNCTION (0x01U)//非法功能码的异常码
- #define MODBUS_EX_ILLEGAL_ADDRESS (0x02U)//非法地址的异常码
- #define MODBUS_EX_ILLEGAL_VALUE (0x03U)//非法数据的异常码
-
- #define MODBUS_READ_COILS_MAX (2000U)//一次ADU最大线圈读取数量
- #define MODBUS_READ_REGS_MAX (125U) //一次ADU最大寄存器读取数量
- #define MODBUS_WRITE_COILS_MAX (1968U)//一次ADU最大线圈写入数量
- #define MODBUS_WRITE_REGS_MAX (123U) //一次ADU最大寄存器写入数量
-
- #define MODBUS_COIL_VALUE_ON (0xFF00U)
- #define MODBUS_COIL_VALUE_OFF (0x0000U)
-
- static UART_HandleTypeDef *ModbusUart;
- static uint8_t ModbusSlaveAddress;
-
- static MODBUS_HISTORY_ITEM ModbusHistory[16];
- static uint16_t ModbusHistoryWriteIndex;
- /**
- * DMA 缓冲区只由 DMA 写入;帧缓冲区在接收回调中完成一次快照,
- * 随后由任务解析,避免 DMA 重启后覆盖尚未处理的数据
- */
- static uint8_t ModbusRxDmaBuffer[MODBUS_RTU_ADU_SIZE_MAX];
- static uint8_t ModbusRxFrame[MODBUS_RTU_ADU_SIZE_MAX];
- static uint8_t ModbusTxFrame[MODBUS_RTU_ADU_SIZE_MAX];
- /* D100~D120 上一次已保存的值,用于检测数据是否变化 */
- static uint16_t ModbusRetainedSnapshot[MODBUS_RETAINED_D_COUNT];
- static volatile uint16_t ModbusRxFrameLength;
- static volatile uint8_t ModbusRxFrameReady;
- static volatile uint8_t ModbusTxBusy;
- static volatile uint32_t ModbusRxEventTick;
- static volatile uint32_t ModbusLastValidFrameTick;
- static volatile uint8_t ModbusHasReceivedValidFrame;
-
- /**
- * 10000 个保持寄存器占用 20000 字节;10000 个线圈按位存储,
- * 占用 1250 字节
- */
- static uint16_t ModbusHoldingRegisters[40000];
-
-
- #pragma location = ".ccmram"
- #pragma data_alignment = 4
- __root static uint16_t ModbusRegistersCcm[29999];
-
- static uint8_t ModbusCoils[(MODBUS_MAP_ITEM_COUNT + 7U) / 8U];
-
- volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics;
-
- /**
- * @brief 计算 Modbus RTU CRC16 校验值
- * @param[in] data 待校验数据
- * @param[in] length 待校验数据长度
- * @return CRC16 校验值
- */
- static uint16_t ModbusCrc16(const uint8_t *data, uint16_t length)
- {
- uint16_t crc = 0xFFFFU;
- uint16_t index;
- uint8_t bit;
-
- for (index = 0U; index < length; index++)
- {
- crc ^= data[index];
-
- for (bit = 0U; bit < 8U; bit++)
- {
- if ((crc & 0x0001U) != 0U)
- {
- crc = (uint16_t)((crc >> 1U) ^ 0xA001U);
- }
- else
- {
- crc >>= 1U;
- }
- }
- }
-
- return crc;
- }
-
- /**
- * @brief 提取一个 16 位无符号整数
- * @param[in] data 两个字节的数据地址
- * @return 转换后的 16 位无符号整数
- */
- static uint16_t ModbusGetU16Be(const uint8_t *data)
- {
- return (uint16_t)(((uint16_t)data[0] << 8U) | data[1]);
- }
-
- /**
- * @brief 提取一个 24 位无符号整数
- * @param[in] data 两个字节的数据地址
- * @return 转换后的 24 位无符号整数
- */
- static uint32_t ModbusGetU24Be(const uint8_t *data)
- {
- return (uint32_t)((uint32_t)data[0] << 16U|((uint16_t)data[1] << 8U) | data[2]);
- }
-
- /**
- * @brief 检查连续数据地址范围是否合法。
- * @param[in] start 起始地址。
- * @param[in] quantity 数据项数量。
- */
- static uint8_t ModbusAddressRangeIsValid(uint16_t start, uint16_t quantity)
- {
- if (start >= MODBUS_MAP_ITEM_COUNT)
- {
- return 0U;
- }
-
- // 先做减法再比较,避免溢出
- return (quantity <= (MODBUS_MAP_ITEM_COUNT - start)) ? 1U : 0U;
- }
-
- /**
- * @brief 读取已经确认地址合法的线圈。
- * @param[in] address 线圈地址。
- * @return 线圈状态,取值为 0 或 1。
- */
- static uint8_t ModbusCoilGetUnchecked(uint16_t address)
- {
- uint8_t mask = (uint8_t)(1U << (address & 0x0007U));
-
- return ((ModbusCoils[address >> 3U] & mask) != 0U) ? 1U : 0U;
- }
-
- /**
- * @brief 设置已经确认地址合法的线圈。
- * @param[in] address 线圈地址。
- * @param[in] state 0 表示复位,非 0 表示置位。
- */
- static void ModbusCoilSetUnchecked(uint16_t address, uint8_t state)
- {
- uint8_t mask = (uint8_t)(1U << (address & 0x0007U));
-
- if (state != 0U)
- {
- ModbusCoils[address >> 3U] |= mask;
- }
- else
- {
- ModbusCoils[address >> 3U] &= (uint8_t)(~mask);
- }
- }
-
- /**
- * @brief 启动 USART DMA 空闲接收。
- * @retval HAL_OK DMA 接收启动成功。
- * @retval HAL_BUSY 串口未配置或发送尚未结束。
- * @return 其他 HAL 状态表示 DMA 接收启动失败。
- */
- static HAL_StatusTypeDef ModbusStartReceive(void)
- {
- HAL_StatusTypeDef status;
-
- if (ModbusTxBusy != 0U)
- {
- return HAL_BUSY;
- }
-
- status = HAL_UARTEx_ReceiveToIdle_DMA(ModbusUart,
- ModbusRxDmaBuffer,
- sizeof(ModbusRxDmaBuffer));
-
- if ((status == HAL_OK) && (ModbusUart->hdmarx != NULL))
- {
- /*
- * 普通 Modbus 帧只应在 IDLE 或缓冲区满时交给应用。
- * 关闭 DMA 半传输中断,避免长帧在一半位置被误认为完整帧。
- */
- __HAL_DMA_DISABLE_IT(ModbusUart->hdmarx, DMA_IT_HT);
- }
-
- return status;
- }
-
-
-
- /**
- * @brief 在 RTU 帧末尾追加 CRC 低字节和高字节。
- * @param[in,out] frame 待追加 CRC 的帧缓冲区。
- * @param[in] payloadLength 不包含 CRC 的有效载荷长度。
- */
- static void ModbusAppendCrc(uint8_t *frame, uint16_t payloadLength)
- {
- uint16_t crc = ModbusCrc16(frame, payloadLength);
-
- /* Modbus RTU 在线路上传输 CRC 低字节在前、高字节在后。 */
- frame[payloadLength] = (uint8_t)(crc & 0x00FFU);
- frame[payloadLength + 1U] = (uint8_t)(crc >> 8U);
- }
-
- /**
- * @brief 构造 Modbus 异常响应。
- * @param[in] function 请求功能码。
- * @param[in] exception 异常码。
- * @return 异常响应 ADU 长度。
- */
- static uint16_t ModbusBuildException(uint8_t function, uint8_t exception)
- {
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = (uint8_t)(function | 0x80U);
- ModbusTxFrame[2] = exception;
- ModbusAppendCrc(ModbusTxFrame, 3U);
-
- return 5U;
- }
-
- /**
- * @brief 处理读线圈功能码 0x01
- * @param[in] request RTU 请求帧
- * @param[in] requestLength 请求帧长度
- * @return 待发送响应长度,异常请求返回异常响应长度
- */
- static uint16_t ModbusProcessReadCoils(const uint8_t *request, uint16_t requestLength)
- {
-
- uint16_t start;
- uint16_t quantity;
- uint16_t index;
- uint8_t byteCount;
-
- if (requestLength != 8U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- start = ModbusGetU16Be(&request[2]);
- quantity = ModbusGetU16Be(&request[4]);
-
- if ((quantity == 0U) || (quantity > MODBUS_READ_COILS_MAX))//数量0或者数量大于最大值
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- if (ModbusAddressRangeIsValid(start, quantity) == 0U)//地址检查
- {
- ModbusSlaveStatistics.illegalAddressCount++;
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS);
- }
-
- byteCount = (uint8_t)((quantity + 7U) / 8U);
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = 0X01;
- ModbusTxFrame[2] = byteCount;
- (void)memset(&ModbusTxFrame[3], 0, byteCount);
-
- for (index = 0U; index < quantity; index++)
- {
- if (ModbusCoilGetUnchecked((uint16_t)(start + index)) != 0U)
- {
- ModbusTxFrame[3U + (index >> 3U)] |= (uint8_t)(1U << (index & 0x0007U));
-
- }
- }
-
- ModbusAppendCrc(ModbusTxFrame, (uint16_t)(3U + byteCount));
- return (uint16_t)(5U + byteCount);
- }
-
- /**
- * @brief 处理读保持寄存器功能码 0x03
- * @param[in] request RTU 请求帧
- * @param[in] requestLength 请求帧长度
- * @return 待发送响应长度,异常请求返回异常响应长度
- */
- static uint16_t ModbusProcessReadHolding(const uint8_t *request,uint16_t requestLength)
-
- {
- uint16_t start;
- uint16_t quantity;
- uint16_t index;
- uint16_t value;
-
- if (requestLength != 8U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- start = ModbusGetU16Be(&request[2]);
- quantity = ModbusGetU16Be(&request[4]);
-
- if ((quantity == 0U) || (quantity > MODBUS_READ_REGS_MAX))//数量0或者数量大于最大值
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- if (ModbusAddressRangeIsValid(start, quantity) == 0U)//地址检查
- {
- ModbusSlaveStatistics.illegalAddressCount++;
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS);
- }
-
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = 0X03;
- ModbusTxFrame[2] = (uint8_t)(quantity * 2U);
-
- for (index = 0U; index < quantity; index++)
- {
- value = ModbusHoldingRegisters[start + index];
- ModbusTxFrame[3U + index * 2U] = (uint8_t)(value >> 8U);
- ModbusTxFrame[4U + index * 2U] = (uint8_t)(value & 0x00FFU);
- }
-
- ModbusAppendCrc(ModbusTxFrame, (uint16_t)(3U + quantity * 2U));
- return (uint16_t)(5U + quantity * 2U);
- }
-
- /**
- * @brief 处理写单个保持寄存器功能码 0x06。
- * @param[in] request RTU 请求帧。
- * @param[in] requestLength 请求帧长度。
- * @param[in] isBroadcast 非 0 表示当前请求为广播。
- * @return 单播响应长度;广播或无法响应时返回 0。
- */
- static uint16_t ModbusProcessWriteSingleRegister(
- const uint8_t *request,
- uint16_t requestLength,
- uint8_t isBroadcast)
- {
- uint16_t address;
- uint16_t value;
-
- if (requestLength != 8U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- address = ModbusGetU16Be(&request[2]);
- value = ModbusGetU16Be(&request[4]);
-
- if (address >= MODBUS_MAP_ITEM_COUNT)
- {
- ModbusSlaveStatistics.illegalAddressCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS);
- }
-
- ModbusHoldingRegisters[address] = value;
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- /* 0x06 的正常响应必须原样回显请求的前 6 个字节。 */
- (void)memcpy(ModbusTxFrame, request, 6U);
- ModbusAppendCrc(ModbusTxFrame, 6U);
- return 8U;
- }
-
- /**
- * @brief 处理写单个线圈功能码 0x05。
- * @param[in] request RTU 请求帧。
- * @param[in] requestLength 请求帧长度。
- * @param[in] isBroadcast 非 0 表示当前请求为广播。
- * @return 单播响应长度;广播或无法响应时返回 0。
- */
- static uint16_t ModbusProcessWriteSingleCoil(
- const uint8_t *request,
- uint16_t requestLength,
- uint8_t isBroadcast)
- {
- uint16_t address;
- uint16_t value;
-
- if (requestLength != 8U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- address = ModbusGetU16Be(&request[2]);
- value = ModbusGetU16Be(&request[4]);
-
- /*
- * 0x05 只接受 0xFF00(线圈置位)和 0x0000(线圈复位);
- * 其他数值属于非法数据值。
- */
- if ((value != MODBUS_COIL_VALUE_ON)
- && (value != MODBUS_COIL_VALUE_OFF))
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- if (address >= MODBUS_MAP_ITEM_COUNT)
- {
- ModbusSlaveStatistics.illegalAddressCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS);
- }
-
- ModbusCoilSetUnchecked(
- address,
- (value == MODBUS_COIL_VALUE_ON) ? 1U : 0U);
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- /* 0x05 正常应答原样回显请求的前 6 个字节,再追加 CRC。 */
- (void)memcpy(ModbusTxFrame, request, 6U);
- ModbusAppendCrc(ModbusTxFrame, 6U);
- return 8U;
- }
-
- /**
- * @brief 处理写多个线圈功能码 0x0F。
- * @param[in] request RTU 请求帧。
- * @param[in] requestLength 请求帧长度。
- * @param[in] isBroadcast 非 0 表示当前请求为广播。
- * @return 单播响应长度;广播或无法响应时返回 0。
- */
- static uint16_t ModbusProcessWriteMultipleCoils(
- const uint8_t *request,
- uint16_t requestLength,
- uint8_t isBroadcast)
- {
- uint16_t start;
- uint16_t quantity;
- uint16_t index;
- uint8_t byteCount;
- uint8_t expectedByteCount;
-
- if (requestLength < 9U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- start = ModbusGetU16Be(&request[2]);
- quantity = ModbusGetU16Be(&request[4]);
- byteCount = request[6];
- expectedByteCount = (uint8_t)((quantity + 7U) / 8U);
-
- if ((quantity == 0U)
- || (quantity > MODBUS_WRITE_COILS_MAX)
- || (byteCount != expectedByteCount)
- || (requestLength != (uint16_t)(9U + byteCount)))
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- if (ModbusAddressRangeIsValid(start, quantity) == 0U)
- {
- ModbusSlaveStatistics.illegalAddressCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS);
- }
-
- for (index = 0U; index < quantity; index++)
- {
- uint8_t state;
-
- state = (uint8_t)((request[7U + (index >> 3U)]
- >> (index & 0x0007U))
- & 0x01U);
- ModbusCoilSetUnchecked((uint16_t)(start + index), state);
- }
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = 0X0F;
- (void)memcpy(&ModbusTxFrame[2], &request[2], 4U);
- ModbusAppendCrc(ModbusTxFrame, 6U);
- return 8U;
- }
-
- /**
- * @brief 处理写多个保持寄存器功能码 0x10。
- * @param[in] request RTU 请求帧。
- * @param[in] requestLength 请求帧长度。
- * @param[in] isBroadcast 非 0 表示当前请求为广播。
- * @return 单播响应长度;广播或无法响应时返回 0。
- */
- static uint16_t ModbusProcessWriteMultipleRegisters(
- const uint8_t *request,
- uint16_t requestLength,
- uint8_t isBroadcast)
- {
- uint16_t start;
- uint16_t quantity;
- uint16_t index;
- uint8_t byteCount;
-
- if (requestLength < 9U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- start = ModbusGetU16Be(&request[2]);
- quantity = ModbusGetU16Be(&request[4]);
- byteCount = request[6];
-
- if ((quantity == 0U)
- || (quantity > MODBUS_WRITE_REGS_MAX)
- || (byteCount != (uint8_t)(quantity * 2U))
- || (requestLength != (uint16_t)(9U + byteCount)))
- {
- ModbusSlaveStatistics.illegalValueCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- if (ModbusAddressRangeIsValid(start, quantity) == 0U)
- {
- ModbusSlaveStatistics.illegalAddressCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS);
- }
-
- for (index = 0U; index < quantity; index++)
- {
- ModbusHoldingRegisters[start + index] =
- ModbusGetU16Be(&request[7U + index * 2U]);
- }
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = 0X10;
- (void)memcpy(&ModbusTxFrame[2], &request[2], 4U);
- ModbusAppendCrc(ModbusTxFrame, 6U);
- return 8U;
- }
-
-
- /**
- * @brief 处理读取扩展地址保持寄存器功能码0x48
- * @param[in] request RTU请求帧
- * @param[in] requestLength 请求帧长度
- * @return 待发送响应长度,异常请求返回异常响应长度
- */
- static uint16_t ModbusProcessReadBigHolding(
- const uint8_t *request,
- uint16_t requestLength)
- {
- uint32_t start;
- uint32_t currentAddress;
- uint16_t quantity;
- uint16_t index;
- uint16_t value;
-
- /* 请求帧:站号1 + 功能码1 + 地址3 + 数量2 + CRC2。 */
- if (requestLength != 9U)
- {
- ModbusSlaveStatistics.illegalValueCount++;
-
- return ModbusBuildException(
- request[1],
- MODBUS_EX_ILLEGAL_VALUE);
- }
-
- /* 提取24位起始地址和16位寄存器数量。 */
- start = ModbusGetU24Be(&request[2]);
- quantity = ModbusGetU16Be(&request[5]);
-
- /* 一次最多读取125个寄存器。 */
- if ((quantity == 0U) ||
- (quantity > MODBUS_READ_REGS_MAX))
- {
- ModbusSlaveStatistics.illegalValueCount++;
-
- return ModbusBuildException(request[1],MODBUS_EX_ILLEGAL_VALUE);
-
-
- }
-
- /*
- * 普通SRAM有40000个寄存器,CCMRAM有29999个寄存器,
- * 总地址范围为0~69998。
- */
- if ((start >= 69999UL) || ((uint32_t)quantity > (69999UL - start)))
-
- {
- ModbusSlaveStatistics.illegalAddressCount++;
-
- return ModbusBuildException(request[1],MODBUS_EX_ILLEGAL_ADDRESS);
-
-
- }
-
- /* 组成正常响应帧头。 */
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = 0x48U;
- ModbusTxFrame[2] = (uint8_t)(quantity * 2U);
-
- for (index = 0U; index < quantity; index++)
- {
- currentAddress = start + (uint32_t)index;
-
- /*
- * 地址0~39999位于普通SRAM;
- * 地址40000~69998位于CCMRAM。
- */
- if (currentAddress < 40000UL)
- {
- value = ModbusHoldingRegisters[currentAddress];
- }
- else
- {
- value = ModbusRegistersCcm[currentAddress - 40000UL];
-
- }
-
- /* 每个寄存器按照高字节、低字节装入响应帧。 */
- ModbusTxFrame[3U + index * 2U] = (uint8_t)(value >> 8U);
- ModbusTxFrame[4U + index * 2U] = (uint8_t)(value & 0x00FFU);
-
- }
- /* 添加CRC。 */
- ModbusAppendCrc( ModbusTxFrame, (uint16_t)(3U + quantity * 2U));
-
- return (uint16_t)(5U + quantity * 2U);
- }
-
- /**
- * @brief 校验并分发一帧 Modbus RTU 请求。
- * @param[in] request RTU 请求帧。
- * @param[in] requestLength 请求帧长度。
- * @return 待发送响应长度;无需响应时返回 0。
- */
- static uint16_t ModbusProcessRequest(const uint8_t *request,uint16_t requestLength)
- {
- uint16_t calculatedCrc;
- uint16_t receivedCrc;
- uint8_t isBroadcast;
-
- if (requestLength < 4U)
- {
- return 0U;
- }
-
- calculatedCrc = ModbusCrc16(request, (uint16_t)(requestLength - 2U));
- receivedCrc =
- (uint16_t)(request[requestLength - 2U]
- | ((uint16_t)request[requestLength - 1U] << 8U));
-
- if (calculatedCrc != receivedCrc)//CRC校验
- {
- ModbusSlaveStatistics.crcErrorCount++;
- return 0U;
- }
-
- if ((request[0] != ModbusSlaveAddress)
- && (request[0] != MODBUS_BROADCAST_ADDRESS))//非法从站地址
- {
- ModbusSlaveStatistics.ignoredAddressCount++;
- return 0U;
- }
-
- isBroadcast = (request[0] == MODBUS_BROADCAST_ADDRESS) ? 1U : 0U;//是否广播请求
- ModbusSlaveStatistics.validFrameCount++;
- ModbusLastValidFrameTick = HAL_GetTick();
- ModbusHasReceivedValidFrame = 1U;
-
- switch (request[1])
- {
- case 0X01U://读线圈
- // 广播请求不允许读取,从站不作响应。
- return (isBroadcast != 0U) ? 0U :
- ModbusProcessReadCoils(request, requestLength);
-
- case 0X03U://读保持寄存器
- return (isBroadcast != 0U) ? 0U :
- ModbusProcessReadHolding(request, requestLength);
-
- case 0x05U://写单个线圈
- return ModbusProcessWriteSingleCoil(request,
- requestLength,
- isBroadcast);
-
- case 0x06U://写单个保持寄存器
- return ModbusProcessWriteSingleRegister(request,
- requestLength,
- isBroadcast);
-
- case 0x0FU://写多个线圈
- return ModbusProcessWriteMultipleCoils(request,
- requestLength,
- isBroadcast);
-
- case 0x10U://写多个保持寄存器
- return ModbusProcessWriteMultipleRegisters(request,
- requestLength,
- isBroadcast);
-
- case 0x48U://读大地址保持寄存器
- return ModbusProcessReadBigHolding(request, requestLength);
-
- default://未知功能码
- ModbusSlaveStatistics.illegalFunctionCount++;
- return (isBroadcast != 0U) ? 0U :
- ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_FUNCTION);
- }
- }
-
- HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart,
- uint8_t slaveAddress)
- {
-
- ModbusUart = huart;
- ModbusSlaveAddress = slaveAddress;
-
- ModbusHoldingRegisters[HMI_REG_DEVICE_ID] = 0xF407U;
-
- return ModbusStartReceive();
- }
-
- void ModbusSlavePoll(void)
- {
- uint16_t responseLength;
-
- if ((ModbusRxFrameReady == 0U) || (ModbusTxBusy != 0U))
- {
- return;
- }
-
-
-
- responseLength = ModbusProcessRequest(ModbusRxFrame, ModbusRxFrameLength);
- ModbusHistorySave(OSTimeGet() / 1000,ModbusRxFrame,
- ModbusRxFrameLength,
- ModbusTxFrame,
- responseLength);
-
-
-
- if (responseLength > 0U)
- {
- ModbusTxBusy = 1U;
-
- if (HAL_UART_Transmit_DMA(ModbusUart,
- ModbusTxFrame,
- responseLength) == HAL_OK)
- {
- ModbusSlaveStatistics.txFrameCount++;
- }
- else
- {
- ModbusTxBusy = 0U;
- ModbusSlaveStatistics.uartErrorCount++;
- (void)ModbusStartReceive();//重启DMA接收
- }
- }
- else
- {
- (void)ModbusStartReceive();
- }
-
- /*
- * 当前帧;处理完成后再释放帧槽。
- */
- ModbusRxFrameReady = 0U;
- }
-
- void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size)
- {
-
- ModbusSlaveStatistics.rxEventCount++;//串口接收事件计数
-
- if ((size > 0U) && (size <= MODBUS_RTU_ADU_SIZE_MAX))
- {
- if (ModbusRxFrameReady == 0U)
- {
- (void)memcpy(ModbusRxFrame, ModbusRxDmaBuffer, size);
- ModbusRxFrameLength = size;
- ModbusRxEventTick = HAL_GetTick();
- ModbusRxFrameReady = 1U;
- }
- else
- {
- //前一帧未处理完毕
- ModbusSlaveStatistics.droppedFrameCount++;
- }
- }
- else
- {
- //长度异常帧
- ModbusSlaveStatistics.droppedFrameCount++;
- (void)ModbusStartReceive();
- }
- }
-
- void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart)
- {
- if ((huart != ModbusUart) || (ModbusUart == NULL))
- {
- return;
- }
-
- ModbusTxBusy = 0U;
- (void)ModbusStartReceive();//重启DMA接收
- }
-
- void ModbusSlaveOnUartError(UART_HandleTypeDef *huart)
- {
- if ((huart != ModbusUart) || (ModbusUart == NULL))
- {
- return;
- }
-
- ModbusSlaveStatistics.uartErrorCount++;
- ModbusTxBusy = 0U;
- (void)HAL_UART_Abort(huart);//立即终止这个串口当前正在进行的发送和接收操作
- (void)ModbusStartReceive();//重启DMA接收
- }
-
- uint8_t ModbusSlaveSetHoldingRegister(uint16_t address, uint16_t value)
- {
- if (address >= MODBUS_MAP_ITEM_COUNT)
- {
- return 0U;
- }
-
- ModbusHoldingRegisters[address] = value;
- return 1U;
- }
-
- uint8_t ModbusSlaveGetHoldingRegister(uint16_t address, uint16_t *value)
- {
- if ((address >= MODBUS_MAP_ITEM_COUNT) || (value == NULL))
- {
- return 0U;
- }
-
- *value = ModbusHoldingRegisters[address];
- return 1U;
- }
-
- uint8_t ModbusSlaveSetCoil(uint16_t address, uint8_t state)
- {
- if (address >= MODBUS_MAP_ITEM_COUNT)
- {
- return 0U;
- }
-
- ModbusCoilSetUnchecked(address, state);
- return 1U;
- }
-
- uint8_t ModbusSlaveGetCoil(uint16_t address, uint8_t *state)
- {
- if ((address >= MODBUS_MAP_ITEM_COUNT) || (state == NULL))
- {
- return 0U;
- }
-
- *state = ModbusCoilGetUnchecked(address);
- return 1U;
- }
-
- uint8_t ModbusSlaveIsConnected(uint32_t timeoutMs)
- {
- if (ModbusHasReceivedValidFrame == 0U)
- {
- return 0U;
- }
-
- return ((HAL_GetTick() - ModbusLastValidFrameTick) <= timeoutMs)
- ? 1U
- : 0U;
- }
-
- //上电恢复函数
- void ModbusRetainedRegistersLoad(void)
- {
- uint16_t index;
-
- if (backupData->magic == MODBUS_BACKUP_MAGIC)
- {
- for (index = 0U; index < MODBUS_RETAINED_D_COUNT;index++)
- {
- ModbusHoldingRegisters[MODBUS_RETAINED_D_START + index] =
- backupData->retainedD[index];
- }
- }
- else
- {
- for (index = 0U;index < MODBUS_RETAINED_D_COUNT;index++)
- {
- ModbusHoldingRegisters[
- MODBUS_RETAINED_D_START + index] = 0U;
-
- backupData->retainedD[index] = 0U;
- }
-
- /*
- * 数据初始化完成后最后写magic,避免初始化中途断电
- * 却把不完整数据标记成有效。
- */
- backupData->magic = MODBUS_BACKUP_MAGIC;
- }
- }
- void ModbusRetainedRegistersPoll(void)
- {
- uint16_t index;
- // uint16_t address;
- uint16_t value;
-
- for(index=0;index<MODBUS_RETAINED_D_COUNT;index++)
- {
- value=ModbusHoldingRegisters[MODBUS_RETAINED_D_START +index];
- if(value != ModbusRetainedSnapshot[index])
- {
- backupData->retainedD[index]=value;
- }
-
- ModbusRetainedSnapshot[index] = value;
- }
-
-
-
-
- }
- static void ModbusHistorySave(
- uint32_t tick,
- const uint8_t *request,
- uint16_t requestLength,
- const uint8_t *response,
- uint16_t responseLength)
- {
- MODBUS_HISTORY_ITEM *item;
-
- if(requestLength > 256U)
- {
- requestLength = 256U;
- }
-
- if(responseLength > 256U)
- {
- responseLength = 256U;
- }
-
- item = &ModbusHistory[ModbusHistoryWriteIndex];
-
- item->tick = tick;
- item->requestLength = requestLength;
- item->responseLength = responseLength;
-
- (void)memcpy(
- item->request,
- request,
- requestLength);
-
- if(responseLength > 0U)
- {
- (void)memcpy(
- item->response,
- response,
- responseLength);
- }
-
- ModbusHistoryWriteIndex++;
-
- if(ModbusHistoryWriteIndex >= 16U)
- {
- ModbusHistoryWriteIndex = 0U;
- }
- }
- void HistorySaveToRegisters(void)
- {
- // (void)memcpy(
- // &ModbusHoldingRegisters[1000],
- // ModbusHistory,
- // sizeof(ModbusHistory));
-
- uint16_t index;
-
- if(ModbusHistoryWriteIndex == 0U)
- {
- index = 15U;
- }
- else
- {
- index = ModbusHistoryWriteIndex - 1U;
- }
-
- (void)memcpy(
- &ModbusHoldingRegisters[
- 1000U + index * 260U],
- &ModbusHistory[index],
- sizeof(ModbusHistory[index]));
- }
|