25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

169 satır
6.6 KiB

  1. import unittest
  2. import plsr_test
  3. class FakeSerial:
  4. def __init__(self, response):
  5. self.response = response
  6. self.rx = bytearray()
  7. self.writes = []
  8. @property
  9. def in_waiting(self):
  10. return len(self.rx)
  11. def reset_input_buffer(self):
  12. self.rx.clear()
  13. def write(self, data):
  14. self.writes.append(bytes(data))
  15. self.rx.extend(bytes.fromhex("40 00") + self.response)
  16. return len(data)
  17. def flush(self):
  18. pass
  19. def read(self, size):
  20. chunk_size = min(size, 3, len(self.rx))
  21. data = bytes(self.rx[:chunk_size])
  22. del self.rx[:chunk_size]
  23. return data
  24. class ProtocolTests(unittest.TestCase):
  25. def test_known_crc(self):
  26. self.assertEqual(plsr_test.crc16(bytes.fromhex("01 03 00 00 00 0A")), 0xCDC5)
  27. def test_status_request(self):
  28. frame = plsr_test.read_holding_request(1, 0, 32)
  29. self.assertEqual(frame.hex(" "), "01 03 00 00 00 20 44 12")
  30. def test_write_register_request(self):
  31. frame = plsr_test.write_register_request(1, 100, 1)
  32. self.assertEqual(frame, plsr_test.with_crc(bytes.fromhex("01 06 00 64 00 01")))
  33. def test_parser_recovers_from_stale_bytes(self):
  34. response = plsr_test.with_crc(bytes.fromhex("01 03 04 00 05 00 06"))
  35. buffer = bytearray(bytes.fromhex("40 00 00 03 40") + response)
  36. self.assertEqual(plsr_test.extract_response(buffer, 1, 3), response)
  37. def test_parser_waits_for_partial_frame(self):
  38. response = plsr_test.with_crc(bytes.fromhex("01 03 04 00 05 00 06"))
  39. buffer = bytearray(response[:5])
  40. self.assertIsNone(plsr_test.extract_response(buffer, 1, 3))
  41. buffer.extend(response[5:])
  42. self.assertEqual(plsr_test.extract_response(buffer, 1, 3), response)
  43. def test_snapshot_combines_high_and_low_words(self):
  44. snapshot = plsr_test.Snapshot(5, 2, 10, 0, 0, (1 << 16) | 2, 4, 1)
  45. self.assertEqual(snapshot.total_pulses, 65538)
  46. self.assertEqual(snapshot.state_name, "Done")
  47. def test_spec_snapshot_reads_stop_reason_and_signed_total(self):
  48. class SnapshotClient(plsr_test.ModbusRtuClient):
  49. def read_holding(self, address, count):
  50. if address == plsr_test.REG_MONITOR_TOTAL_PULSES:
  51. return [0xFFFF, 0xFFFE, 0, 2, 6, 1, 0, 1]
  52. return [2, 1]
  53. snapshot = SnapshotClient("FAKE", protocol=plsr_test.MAP_SPEC).read_snapshot()
  54. self.assertEqual(snapshot.total_pulses, -2)
  55. self.assertEqual(snapshot.stop_reason, 1)
  56. self.assertEqual(snapshot.state_name, "Stopped")
  57. def test_client_handles_fragmented_noisy_response(self):
  58. response = plsr_test.with_crc(bytes.fromhex("01 03 04 00 05 00 06"))
  59. fake = FakeSerial(response)
  60. client = plsr_test.ModbusRtuClient("FAKE", timeout=0.1, retries=0)
  61. client._serial = fake
  62. self.assertEqual(client.read_holding(0, 2), [5, 6])
  63. self.assertEqual(len(fake.writes), 1)
  64. def test_signed_double_word_round_trip(self):
  65. self.assertEqual(plsr_test.encode_i32(-2147483648), (0x8000, 0x0000))
  66. self.assertEqual(plsr_test.encode_i32(-1), (0xFFFF, 0xFFFF))
  67. self.assertEqual(plsr_test.decode_i32(0x7FFF, 0xFFFF), 2147483647)
  68. self.assertEqual(plsr_test.decode_i32(0x8000, 0), -2147483648)
  69. def test_spec_configuration_validation(self):
  70. cfg = plsr_test.PlsrConfiguration(
  71. pulse_output=3, direction_output=3, segment_count=10,
  72. segments=[plsr_test.SegmentParameters(100000, -1, 4, 10, 20, 0) for _ in range(10)],
  73. )
  74. cfg.validate()
  75. zero_speed_cfg = plsr_test.PlsrConfiguration(
  76. start_speed_hz=0,
  77. end_speed_hz=0,
  78. segments=[plsr_test.SegmentParameters(0, 1)] + [plsr_test.SegmentParameters() for _ in range(9)],
  79. )
  80. zero_speed_cfg.validate()
  81. with self.assertRaisesRegex(ValueError, "frequency must be 1..100000 Hz"):
  82. plsr_test.PlsrConfiguration(default_speed_hz=0).validate()
  83. with self.assertRaises(ValueError):
  84. plsr_test.PlsrConfiguration(segment_count=11).validate()
  85. def test_send_and_run_modes_accept_only_zero_or_one(self):
  86. config = plsr_test.PlsrConfiguration(send_mode=1, run_mode=1)
  87. config.validate()
  88. with self.assertRaises(ValueError):
  89. plsr_test.PlsrConfiguration(send_mode=2).validate()
  90. with self.assertRaises(ValueError):
  91. plsr_test.PlsrConfiguration(run_mode=2).validate()
  92. def test_spec_segment_request_uses_fc16_and_signed_count(self):
  93. frame = plsr_test.write_registers_request(
  94. 1, plsr_test.REG_SEGMENT_BASE,
  95. [100000 >> 16, 100000 & 0xFFFF, 0xFFFF, 0xFFFF, 4, 10, 20, 0],
  96. )
  97. self.assertEqual(frame[1], 0x10)
  98. self.assertEqual(frame[2:6], bytes.fromhex("11 00 00 08"))
  99. self.assertEqual(frame[6], 16)
  100. def test_spec_commands_have_independent_control_bits(self):
  101. client = plsr_test.ModbusRtuClient("FAKE", protocol=plsr_test.MAP_SPEC)
  102. writes = []
  103. client.write_register = lambda address, value: writes.append((address, value))
  104. client.command(plsr_test.COMMAND_STOP)
  105. client.command(plsr_test.COMMAND_IMMEDIATE_STOP)
  106. client.command(plsr_test.COMMAND_CLEAR_COUNT)
  107. client.command(plsr_test.COMMAND_RESET)
  108. client.command(plsr_test.COMMAND_RESTART)
  109. self.assertEqual(writes, [
  110. (plsr_test.REG_CONTROL, plsr_test.CONTROL_STOP),
  111. (plsr_test.REG_CONTROL, plsr_test.CONTROL_IMMEDIATE_STOP),
  112. (plsr_test.REG_CONTROL, plsr_test.CONTROL_CLEAR_COUNT),
  113. (plsr_test.REG_CONTROL, plsr_test.CONTROL_RESET),
  114. (plsr_test.REG_CONTROL, plsr_test.CONTROL_RESTART),
  115. ])
  116. def test_running_frequency_updates_current_segment_only(self):
  117. client = plsr_test.ModbusRtuClient(
  118. "FAKE", protocol=plsr_test.MAP_SPEC
  119. )
  120. snapshots = [
  121. plsr_test.Snapshot(
  122. 2, 1, 1000, 0, 0, 25, 0, 0, 3, plsr_test.MAP_SPEC
  123. ),
  124. plsr_test.Snapshot(
  125. 2, 1, 5000, 0, 0, 25, 0, 0, 3, plsr_test.MAP_SPEC
  126. ),
  127. ]
  128. writes = []
  129. client.read_snapshot = lambda: snapshots.pop(0)
  130. client.write_u32 = lambda address, value: writes.append((address, value))
  131. result = client.set_running_frequency(5000)
  132. expected_address = (
  133. plsr_test.REG_SEGMENT_BASE + 2 * plsr_test.REG_SEGMENT_STRIDE
  134. )
  135. self.assertEqual(writes, [(expected_address, 5000)])
  136. self.assertEqual(result.current_frequency, 5000)
  137. if __name__ == "__main__":
  138. unittest.main(verbosity=2)