|
- import unittest
-
- from modbus_rtu import build_read_holding, build_write_multiple, build_write_single, valid_crc
- from plsr_protocol import (
- PULSE_POINTS,
- SECONDARY_POINTS,
- Command,
- DirectionLogic,
- Register,
- SendMode,
- STATUS_REGISTER_COUNT,
- WaitCondition,
- calculate_execution_total,
- join_i32,
- join_u32,
- parse_status,
- segment_base,
- signed_to_u32,
- split_u32,
- register_read_count,
- )
-
-
- class ParameterTable2026Tests(unittest.TestCase):
- def test_low_word_is_at_low_address(self):
- self.assertEqual(split_u32(0x12345678), [0x5678, 0x1234])
- self.assertEqual(join_u32(0x5678, 0x1234), 0x12345678)
- self.assertEqual(join_i32(0xFF9C, 0xFFFF), -100)
-
- def test_system_and_status_addresses(self):
- self.assertEqual(int(Register.PULSE_POINT), 0x1000)
- self.assertEqual(int(Register.MAX_FREQ_HI), 0x1015)
- self.assertEqual(register_read_count(), 0x16)
- self.assertEqual(int(Register.CUMULATIVE_POSITION_LO), 0x2000)
- self.assertEqual(int(Register.CONTROL), 0x3000)
-
- def test_segment_stride(self):
- self.assertEqual(segment_base(0), 0x1100)
- self.assertEqual(segment_base(9), 0x1190)
-
- def test_start_control_frame(self):
- frame = build_write_single(1, int(Register.CONTROL), int(Command.START))
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[:6], bytes.fromhex("01 06 30 00 00 01"))
-
- def test_segment_frame_layout(self):
- values = split_u32(1000) + split_u32((-200) & 0xFFFFFFFF)
- values += [int(WaitCondition.WAIT_TIME), 500, 0, 2]
- frame = build_write_multiple(1, segment_base(0), values)
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[2:7], bytes.fromhex("11 00 00 08 10"))
-
- def test_status_read_frame(self):
- frame = build_read_holding(
- 1, int(Register.CUMULATIVE_POSITION_LO), STATUS_REGISTER_COUNT
- )
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[:6], bytes.fromhex("01 03 20 00 00 1B"))
-
- def test_status_pulse_counts(self):
- status = parse_status([30, 0, 0, 0, 2, 0, 0, 10, 0, 30, 0])
- self.assertEqual(status["current_pulses"], 10)
- self.assertEqual(status["total_pulses"], 30)
-
- def test_diagnostic_status_values(self):
- registers = [0] * STATUS_REGISTER_COUNT
- registers[11] = 0x001E
- registers[12] = 2
- registers[13] = 3
- registers[14:16] = split_u32(1000)
- registers[16:18] = split_u32(1000)
- registers[18:20] = split_u32(5000)
- registers[20:22] = split_u32(4998)
- registers[22:24] = split_u32(2)
- status = parse_status(registers)
- self.assertEqual(status["diagnostic_expected_pulses"], 1000)
- self.assertEqual(status["diagnostic_observed_pulses"], 1000)
- self.assertEqual(status["diagnostic_actual_frequency"], 4998)
- self.assertEqual(status["diagnostic_max_frequency_error"], 2)
-
- def test_ab_reverse_segment_uses_signed_pulse_count(self):
- self.assertEqual(split_u32(signed_to_u32(-100)), [0xFF9C, 0xFFFF])
-
- def test_b_phase_point_encoding(self):
- self.assertEqual(SECONDARY_POINTS[0].split()[0], "Y12")
- self.assertEqual(SECONDARY_POINTS[3].split()[0], "Y15")
-
- def test_output_mode_register(self):
- self.assertEqual(int(Register.OUTPUT_MODE), 0x100F)
-
- def test_send_mode_register_values(self):
- self.assertEqual(int(Register.SEND_MODE), 0x1004)
- self.assertEqual(int(SendMode.COMPLETE), 0)
- self.assertEqual(int(SendMode.FOLLOW), 1)
-
- def test_direction_logic_register_values(self):
- self.assertEqual(int(Register.DIRECTION_LOGIC), 0x1006)
- self.assertEqual(int(DirectionLogic.POSITIVE), 0)
- self.assertEqual(int(DirectionLogic.NEGATIVE), 1)
-
- def test_y3_uses_pf9_tim14(self):
- self.assertEqual(PULSE_POINTS[3], "Y3 / PF9 / TIM14_CH1")
-
- def test_execution_total_starts_from_selected_segment(self):
- segments = [
- (100, 1000, 0),
- (200, 1000, 0),
- (-300, 1000, 0),
- ]
- self.assertEqual(calculate_execution_total(segments, 2), (500, False))
-
- def test_execution_total_follows_jump_and_detects_cycle(self):
- segments = [
- (100, 1000, 3),
- (200, 1000, 0),
- (300, 1000, 1),
- ]
- self.assertEqual(calculate_execution_total(segments, 1), (400, True))
-
- def test_clear_total_control_frame(self):
- frame = build_write_single(
- 1, int(Register.CONTROL), int(Command.CLEAR_TOTAL)
- )
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[:6], bytes.fromhex("01 06 30 00 00 08"))
-
- def test_save_outputs_control_frame(self):
- frame = build_write_single(
- 1, int(Register.CONTROL), int(Command.SAVE_OUTPUTS)
- )
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[:6], bytes.fromhex("01 06 30 00 00 10"))
-
- def test_clear_diagnostic_control_frame(self):
- frame = build_write_single(
- 1, int(Register.CONTROL), int(Command.CLEAR_DIAGNOSTIC)
- )
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[:6], bytes.fromhex("01 06 30 00 00 20"))
-
- def test_runtime_frequency_is_separate_from_default_speed(self):
- self.assertEqual(int(Register.TARGET_FREQ_LO), 0x100B)
- self.assertEqual(int(Register.RUNTIME_FREQ_LO), 0x1016)
- frame = build_write_single(
- 1, int(Register.CONTROL), int(Command.UPDATE_FREQUENCY)
- )
- self.assertTrue(valid_crc(frame))
- self.assertEqual(frame[:6], bytes.fromhex("01 06 30 00 00 40"))
-
-
- if __name__ == "__main__":
- unittest.main()
|