Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

307 rader
10 KiB

  1. /**
  2. * @file modbus_test.c
  3. * @brief Modbus RTU 从站私有功能码单元测试。
  4. * @version 2.1
  5. * @author zengbingjie
  6. * @date 2026-08-02
  7. */
  8. #include <assert.h>
  9. #include <stdint.h>
  10. #include <string.h>
  11. #include "modbus.h"
  12. #define TEST_SLAVE_ADDRESS (1U)
  13. #define TEST_EXTENDED_READ_FRAME_LENGTH (10U)
  14. #define TEST_EXTENDED_READ_RESPONSE_LENGTH (7U)
  15. #define TEST_EXTENDED_WRITE_FRAME_LENGTH (10U)
  16. #define TEST_ODD_READ_FRAME_LENGTH (8U)
  17. #define TEST_ODD_READ_RESPONSE_LENGTH (11U)
  18. #define TEST_ODD_READ_MAX_RESPONSE_LENGTH (251U)
  19. #define TEST_FC_READ_EXTENDED_REGISTER (0x41U)
  20. #define TEST_FC_WRITE_EXTENDED_REGISTER (0x42U)
  21. #define TEST_FC_READ_ODD_COUNT_REGS (0x43U)
  22. static uint16_t TestHoldingRegisters[MODBUS_DATA_POINT_COUNT];
  23. static uint8_t TestCoilStorage[MODBUS_COIL_STORAGE_SIZE];
  24. static uint16_t TestExtendedRegister;
  25. /**
  26. * @brief 向测试请求末尾追加 Modbus RTU CRC。
  27. * @param[in,out] frame 测试请求帧。
  28. * @param[in] payloadLength 未含 CRC 的帧长度。
  29. * @return 无。
  30. */
  31. static void TestAppendCrc(uint8_t *frame, uint16_t payloadLength)
  32. {
  33. uint16_t crcValue;
  34. assert(frame != NULL);
  35. crcValue = ModbusCrc16(frame, payloadLength);
  36. frame[payloadLength] = (uint8_t)(crcValue & 0x00FFU);
  37. frame[payloadLength + 1U] = (uint8_t)(crcValue >> 8U);
  38. }
  39. /**
  40. * @brief 校验响应帧的 CRC 字节序和数值。
  41. * @param[in] frame 响应帧。
  42. * @param[in] frameLength 含 CRC 的帧长度。
  43. * @return 无。
  44. */
  45. static void TestAssertFrameCrc(const uint8_t *frame, uint16_t frameLength)
  46. {
  47. uint16_t expectedCrc;
  48. uint16_t actualCrc;
  49. assert(frame != NULL);
  50. assert(frameLength >= MODBUS_RTU_ADU_MIN_LENGTH);
  51. expectedCrc = ModbusCrc16(frame, frameLength - MODBUS_RTU_CRC_LENGTH);
  52. actualCrc = (uint16_t)frame[frameLength - MODBUS_RTU_CRC_LENGTH]
  53. | ((uint16_t)frame[frameLength - 1U] << 8U);
  54. assert(actualCrc == expectedCrc);
  55. }
  56. /**
  57. * @brief 使用真实数据存储初始化一个从站测试实例。
  58. * @param[out] slave 待初始化的从站。
  59. * @return 无。
  60. */
  61. static void TestInitSlave(MODBUS_SLAVE *slave)
  62. {
  63. assert(slave != NULL);
  64. assert(ModbusSlaveInit(slave, TEST_SLAVE_ADDRESS, TestHoldingRegisters,
  65. TestCoilStorage) == MODBUS_STATUS_OK);
  66. assert(ModbusConfigureExtendedHoldingRegister(slave,
  67. &TestExtendedRegister)
  68. == MODBUS_STATUS_OK);
  69. }
  70. /**
  71. * @brief 回归验证 0x41 仍可读取固定扩展寄存器。
  72. * @return 无。
  73. */
  74. static void TestReadExtendedRegister(void)
  75. {
  76. uint8_t request[TEST_EXTENDED_READ_FRAME_LENGTH] = {
  77. TEST_SLAVE_ADDRESS, TEST_FC_READ_EXTENDED_REGISTER,
  78. 0x00U, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U, 0x00U, 0x00U
  79. };
  80. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  81. uint16_t responseLength;
  82. MODBUS_SLAVE slave;
  83. TestInitSlave(&slave);
  84. TestExtendedRegister = 0x1000U;
  85. TestAppendCrc(request, 8U);
  86. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  87. sizeof(response), &responseLength)
  88. == MODBUS_STATUS_OK);
  89. assert(responseLength == TEST_EXTENDED_READ_RESPONSE_LENGTH);
  90. assert(response[0U] == TEST_SLAVE_ADDRESS);
  91. assert(response[1U] == TEST_FC_READ_EXTENDED_REGISTER);
  92. assert(response[2U] == 2U);
  93. assert(response[3U] == 0x10U);
  94. assert(response[4U] == 0x00U);
  95. TestAssertFrameCrc(response, responseLength);
  96. }
  97. /**
  98. * @brief 验证 0x42 将指定值写入固定扩展寄存器并完整回显。
  99. * @return 无。
  100. */
  101. static void TestWriteExtendedRegister(void)
  102. {
  103. uint8_t request[TEST_EXTENDED_WRITE_FRAME_LENGTH] = {
  104. TEST_SLAVE_ADDRESS, TEST_FC_WRITE_EXTENDED_REGISTER,
  105. 0x00U, 0x01U, 0x00U, 0x00U, 0xBEU, 0xEFU, 0x00U, 0x00U
  106. };
  107. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  108. uint16_t responseLength;
  109. MODBUS_SLAVE slave;
  110. TestInitSlave(&slave);
  111. TestAppendCrc(request, 8U);
  112. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  113. sizeof(response), &responseLength)
  114. == MODBUS_STATUS_OK);
  115. assert(responseLength == TEST_EXTENDED_WRITE_FRAME_LENGTH);
  116. assert(memcmp(response, request, 8U) == 0);
  117. assert(TestExtendedRegister == 0xBEEFU);
  118. TestAssertFrameCrc(response, responseLength);
  119. }
  120. /**
  121. * @brief 验证 0x42 拒绝非 0x00010000 的扩展地址。
  122. * @return 无。
  123. */
  124. static void TestWriteExtendedRegisterRejectsInvalidAddress(void)
  125. {
  126. uint8_t request[TEST_EXTENDED_WRITE_FRAME_LENGTH] = {
  127. TEST_SLAVE_ADDRESS, TEST_FC_WRITE_EXTENDED_REGISTER,
  128. 0x00U, 0x01U, 0x00U, 0x01U, 0x12U, 0x34U, 0x00U, 0x00U
  129. };
  130. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  131. uint16_t responseLength;
  132. MODBUS_SLAVE slave;
  133. TestInitSlave(&slave);
  134. TestAppendCrc(request, 8U);
  135. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  136. sizeof(response), &responseLength)
  137. == MODBUS_STATUS_EXCEPTION);
  138. assert(responseLength == MODBUS_RTU_EXCEPTION_LENGTH);
  139. assert(response[0U] == TEST_SLAVE_ADDRESS);
  140. assert(response[1U]
  141. == (TEST_FC_WRITE_EXTENDED_REGISTER | 0x80U));
  142. assert(response[2U] == MODBUS_EXCEPTION_ILLEGAL_DATA_ADDR);
  143. TestAssertFrameCrc(response, responseLength);
  144. }
  145. /**
  146. * @brief 验证 0x43 从起始基准地址后的奇数地址读取保持寄存器。
  147. * @return 无。
  148. */
  149. static void TestReadOddAddressRegisters(void)
  150. {
  151. uint8_t request[TEST_ODD_READ_FRAME_LENGTH] = {
  152. TEST_SLAVE_ADDRESS, TEST_FC_READ_ODD_COUNT_REGS,
  153. 0x00U, 0x00U, 0x00U, 0x03U, 0x00U, 0x00U
  154. };
  155. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  156. uint16_t responseLength;
  157. MODBUS_SLAVE slave;
  158. TestInitSlave(&slave);
  159. TestHoldingRegisters[0U] = 0xDEADU;
  160. TestHoldingRegisters[1U] = 0x1234U;
  161. TestHoldingRegisters[2U] = 0xBEEFU;
  162. TestHoldingRegisters[3U] = 0xABCDU;
  163. TestHoldingRegisters[4U] = 0xFEEDU;
  164. TestHoldingRegisters[5U] = 0x0001U;
  165. TestAppendCrc(request, 6U);
  166. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  167. sizeof(response), &responseLength)
  168. == MODBUS_STATUS_OK);
  169. assert(responseLength == TEST_ODD_READ_RESPONSE_LENGTH);
  170. assert(response[0U] == TEST_SLAVE_ADDRESS);
  171. assert(response[1U] == TEST_FC_READ_ODD_COUNT_REGS);
  172. assert(response[2U] == 6U);
  173. assert(response[3U] == 0x12U);
  174. assert(response[4U] == 0x34U);
  175. assert(response[5U] == 0xABU);
  176. assert(response[6U] == 0xCDU);
  177. assert(response[7U] == 0x00U);
  178. assert(response[8U] == 0x01U);
  179. TestAssertFrameCrc(response, responseLength);
  180. }
  181. /**
  182. * @brief 验证 0x43 从偶数基准地址 10 开始读取 D11、D13 和 D15。
  183. * @return 无。
  184. */
  185. static void TestReadOddAddressRegistersFromAddressTen(void)
  186. {
  187. uint8_t request[TEST_ODD_READ_FRAME_LENGTH] = {
  188. TEST_SLAVE_ADDRESS, TEST_FC_READ_ODD_COUNT_REGS,
  189. 0x00U, 0x0AU, 0x00U, 0x03U, 0x00U, 0x00U
  190. };
  191. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  192. uint16_t responseLength;
  193. MODBUS_SLAVE slave;
  194. TestInitSlave(&slave);
  195. TestHoldingRegisters[10U] = 0xDEADU;
  196. TestHoldingRegisters[11U] = 0x1111U;
  197. TestHoldingRegisters[12U] = 0xBEEFU;
  198. TestHoldingRegisters[13U] = 0x1313U;
  199. TestHoldingRegisters[14U] = 0xFEEDU;
  200. TestHoldingRegisters[15U] = 0x1515U;
  201. TestAppendCrc(request, 6U);
  202. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  203. sizeof(response), &responseLength)
  204. == MODBUS_STATUS_OK);
  205. assert(responseLength == TEST_ODD_READ_RESPONSE_LENGTH);
  206. assert(response[2U] == 6U);
  207. assert(response[3U] == 0x11U);
  208. assert(response[4U] == 0x11U);
  209. assert(response[5U] == 0x13U);
  210. assert(response[6U] == 0x13U);
  211. assert(response[7U] == 0x15U);
  212. assert(response[8U] == 0x15U);
  213. TestAssertFrameCrc(response, responseLength);
  214. }
  215. /**
  216. * @brief 验证 0x43 支持最大 123 个奇数地址寄存器。
  217. * @return 无。
  218. */
  219. static void TestReadOddCountRegistersMaximum(void)
  220. {
  221. uint8_t request[TEST_ODD_READ_FRAME_LENGTH] = {
  222. TEST_SLAVE_ADDRESS, TEST_FC_READ_ODD_COUNT_REGS,
  223. 0x00U, 0x00U, 0x00U, 0x7BU, 0x00U, 0x00U
  224. };
  225. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  226. uint16_t responseLength;
  227. MODBUS_SLAVE slave;
  228. TestInitSlave(&slave);
  229. TestHoldingRegisters[245U] = 0x7E57U;
  230. TestAppendCrc(request, 6U);
  231. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  232. sizeof(response), &responseLength)
  233. == MODBUS_STATUS_OK);
  234. assert(responseLength == TEST_ODD_READ_MAX_RESPONSE_LENGTH);
  235. assert(response[0U] == TEST_SLAVE_ADDRESS);
  236. assert(response[1U] == TEST_FC_READ_ODD_COUNT_REGS);
  237. assert(response[2U] == 246U);
  238. assert(response[247U] == 0x7EU);
  239. assert(response[248U] == 0x57U);
  240. TestAssertFrameCrc(response, responseLength);
  241. }
  242. /**
  243. * @brief 验证 0x43 拒绝偶数数量。
  244. * @return 无。
  245. */
  246. static void TestReadOddCountRegistersRejectsEvenCount(void)
  247. {
  248. uint8_t request[TEST_ODD_READ_FRAME_LENGTH] = {
  249. TEST_SLAVE_ADDRESS, TEST_FC_READ_ODD_COUNT_REGS,
  250. 0x00U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U
  251. };
  252. uint8_t response[MODBUS_RTU_ADU_MAX_LENGTH];
  253. uint16_t responseLength;
  254. MODBUS_SLAVE slave;
  255. TestInitSlave(&slave);
  256. TestAppendCrc(request, 6U);
  257. assert(ModbusProcessFrame(&slave, request, sizeof(request), response,
  258. sizeof(response), &responseLength)
  259. == MODBUS_STATUS_EXCEPTION);
  260. assert(responseLength == MODBUS_RTU_EXCEPTION_LENGTH);
  261. assert(response[0U] == TEST_SLAVE_ADDRESS);
  262. assert(response[1U] == (TEST_FC_READ_ODD_COUNT_REGS | 0x80U));
  263. assert(response[2U] == MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
  264. TestAssertFrameCrc(response, responseLength);
  265. }
  266. /**
  267. * @brief 执行 Modbus RTU 私有功能码单元测试。
  268. * @return 0 表示全部测试通过。
  269. */
  270. int main(void)
  271. {
  272. TestReadExtendedRegister();
  273. TestWriteExtendedRegister();
  274. TestWriteExtendedRegisterRejectsInvalidAddress();
  275. TestReadOddAddressRegisters();
  276. TestReadOddAddressRegistersFromAddressTen();
  277. TestReadOddCountRegistersMaximum();
  278. TestReadOddCountRegistersRejectsEvenCount();
  279. return 0;
  280. }