Files
2026-06-09 12:42:15 +08:00

120 lines
4.8 KiB
C++

// 本文件测试下位机/从站侧服务。验证寄存器表读写、完整请求到响应处理、
// 模式切换带来的状态副作用,以及急停后非法模式切换会被拒绝。
#include "line_laser_modbus/device.hpp"
#include "line_laser_modbus/host.hpp"
#include "test_support.hpp"
#include <iostream>
using namespace line_laser_modbus;
namespace {
void test_read_status_request_round_trip() {
DeviceServer device;
HostClient host;
const ByteVector response =
device.process_request(host.make_read_status_request());
const auto status = host.parse_status_response(response);
test_support::require_true(status.has_value(), "device must answer status read");
test_support::require_true(status->mode == WorkMode::StandbyReset,
"initial device mode must be standby");
test_support::require_true(status->state == DeviceState::StandbyReady,
"initial device state must be ready");
}
void test_write_mode_changes_state() {
DeviceServer device;
HostClient host;
const ByteVector ack =
device.process_request(host.make_write_mode_request(WorkMode::OnlineTracking));
test_support::require_true(
host.parse_write_ack(ack, kModeCommandAddress, 1U),
"device must ack valid online tracking mode write");
test_support::require_true(device.bank().mode() == WorkMode::OnlineTracking,
"device mode register must update");
test_support::require_true(device.bank().state() == DeviceState::OnlineTrackingNormal,
"device state must reflect online tracking");
}
void test_emergency_allows_only_standby_exit() {
DeviceServer device;
HostClient host;
const ByteVector emergency_ack =
device.process_request(host.make_write_mode_request(WorkMode::EmergencyStop));
test_support::require_true(host.parse_write_ack(emergency_ack, kModeCommandAddress, 1U),
"emergency mode write must be accepted");
const ByteVector rejected =
device.process_request(host.make_write_mode_request(WorkMode::OnlineTracking));
test_support::require_true(rejected.size() == 5U,
"illegal transition must return exception frame");
test_support::require_equal(rejected[1], static_cast<std::uint8_t>(0x90),
"write exception function code must be 0x90");
test_support::require_true(device.bank().mode() == WorkMode::EmergencyStop,
"illegal transition must not modify mode");
const ByteVector accepted =
device.process_request(host.make_write_mode_request(WorkMode::StandbyReset));
test_support::require_true(host.parse_write_ack(accepted, kModeCommandAddress, 1U),
"standby exit from emergency must be accepted");
}
void test_target_pose_write_and_current_pose_read() {
DeviceServer device;
HostClient host;
const Pose6D target{2000U, 10.0F, 20.0F, 30.0F, 1.0F, 2.0F, 3.0F};
const ByteVector write_ack =
device.process_request(host.make_write_target_pose_request(target));
test_support::require_true(
host.parse_write_ack(write_ack, kTargetPoseAddress, kPoseRegisterCount),
"device must ack target pose write");
const auto stored_target = device.bank().target_pose();
test_support::require_true(stored_target.has_value(),
"device must store target pose registers");
test_support::require_equal(stored_target->timestamp_ms, 2000U,
"target timestamp must store");
test_support::require_float_close(stored_target->z, 30.0F,
"target z must store");
device.bank().set_current_pose(target);
const auto read_response =
device.process_request(host.make_read_current_pose_request());
const auto current = host.parse_current_pose_response(read_response);
test_support::require_true(current.has_value(), "host must parse device pose read");
test_support::require_float_close(current->x, 10.0F, "current x must read");
}
void test_out_of_range_read_returns_exception() {
DeviceServer device;
const ByteVector request =
build_read_request(kDefaultSlaveId, static_cast<std::uint16_t>(0xD06C), 1U);
const ByteVector response = device.process_request(request);
test_support::require_true(response.size() == 5U,
"out-of-range read must return exception frame");
test_support::require_equal(response[1], static_cast<std::uint8_t>(0x83),
"read exception function code must be 0x83");
}
} // 匿名命名空间
int main() {
test_read_status_request_round_trip();
test_write_mode_changes_state();
test_emergency_allows_only_standby_exit();
test_target_pose_write_and_current_pose_read();
test_out_of_range_read_returns_exception();
std::cout << "device_tests passed\n";
return 0;
}