18 #include <gtest/gtest.h> 29 #include <modbus/modbus.h> 32 #include <prbt_hardware_support/ModbusMsgInStamped.h> 40 #include <pilz_testutils/async_test.h> 45 using ::testing::AnyNumber;
46 using ::testing::AtLeast;
47 using ::testing::Return;
48 using ::testing::Throw;
49 using ::testing::InSequence;
50 using ::testing::InvokeWithoutArgs;
51 using ::testing::Invoke;
125 virtual void SetUp();
132 MOCK_METHOD1(modbus_read_cb,
void(ModbusMsgInStamped msg));
142 MATCHER_P(IsSuccessfullRead, vec,
"") {
return arg.holding_registers.data == vec; }
143 MATCHER(IsDisconnect,
"") {
return arg.disconnect.data; }
153 EXPECT_CALL(*mock, init(_,_))
155 .WillOnce(Return(
true));
174 EXPECT_CALL(*mock, init(_,_))
176 .WillOnce(Return(
false))
177 .WillOnce(Return(
true));
196 EXPECT_CALL(*mock, init(_,_))
198 .WillOnce(Return(
true));
218 EXPECT_CALL(*mock, init(_,_))
220 .WillOnce(Return(
false));
239 EXPECT_CALL(*mock, init(_,_))
241 .WillOnce(Return(
false))
242 .WillOnce(Return(
false));
263 EXPECT_CALL(*mock, init(_,_))
265 .WillOnce(Return(
true));
266 EXPECT_CALL(*mock, readHoldingRegister(_,_))
267 .WillOnce(Return(std::vector<uint16_t>{1, 2}))
268 .WillOnce(Return(std::vector<uint16_t>{1, 2}))
269 .WillOnce(Return(std::vector<uint16_t>{3, 4}))
274 EXPECT_CALL(*
this, modbus_read_cb(IsSuccessfullRead(std::vector<uint16_t>{1, 2})))
276 EXPECT_CALL(*
this, modbus_read_cb(IsSuccessfullRead(std::vector<uint16_t>{3, 4})))
278 EXPECT_CALL(*
this, modbus_read_cb(IsDisconnect()))
280 .WillOnce(ACTION_OPEN_BARRIER_VOID(
"disconnected"));
291 EXPECT_NO_THROW(client.run());
292 BARRIER(
"disconnected");
302 EXPECT_CALL(*mock, init(_,_)).Times(0);
303 EXPECT_CALL(*mock, readHoldingRegister(_,_)).Times(0);
304 EXPECT_CALL(*
this, modbus_read_cb(_)).Times(0);
323 EXPECT_CALL(*mock, init(_,_))
325 .WillOnce(Return(
true));
326 ON_CALL(*mock, readHoldingRegister(_,_)).WillByDefault(Return(std::vector<uint16_t>{3, 4}));
327 ON_CALL(*
this, modbus_read_cb(IsSuccessfullRead(std::vector<uint16_t>{3,4})))
328 .WillByDefault(Return());
333 auto client = std::make_shared< PilzModbusClient >(nh_,registers,std::move(mock),
341 EXPECT_TRUE(client->isRunning());
343 EXPECT_FALSE(client->isRunning());
355 const std::string topic_name {
"test_topic_name"};
360 auto client = std::make_shared< PilzModbusClient >(nh_,registers,std::move(mock),
377 EXPECT_CALL(*mock, init(_,_))
379 .WillOnce(Return(
true));
381 EXPECT_CALL(*mock, setResponseTimeoutInMs(response_timeout)).Times(1);
386 auto client = std::make_shared< PilzModbusClient >(nh_,registers,std::move(mock),
401 : register_index_(register_index)
407 RegCont vec( static_cast<RegCont::size_type>(nb) , 0u);
408 vec.at(register_index_) = curr_count_;
420 uint16_t curr_count_ {0};
426 void add(ModbusMsgInStamped msg)
428 std::unique_lock<std::mutex> lk(m_);
429 buffer_ = msg.holding_registers.data.at(0);
434 std::unique_lock<std::mutex> lk(m_);
460 std::vector<double> checked_frequencies {20.0, 40.0, 60.0};
462 for(
const auto& expected_read_frequency : checked_frequencies)
466 EXPECT_CALL(*mock, init(_,_))
468 .WillOnce(Return(
true));
471 ON_CALL(*mock, readHoldingRegister(_, _))
476 ON_CALL(*
this, modbus_read_cb(_))
482 auto client = std::make_shared< PilzModbusClient >(nh_,registers,std::move(mock),
485 expected_read_frequency);
493 ASSERT_TRUE(client->isRunning());
498 auto final_value = buffer.
get();
503 auto actual_frequency = (final_value - 1) / (time_stop - time_start).toSec();
504 EXPECT_NEAR(expected_read_frequency, actual_frequency, 0.1 * expected_read_frequency);
506 EXPECT_FALSE(client->isRunning());
520 EXPECT_CALL(*mock, init(_,_))
522 .WillOnce(Return(
true));
524 ON_CALL(*mock, readHoldingRegister(_, _))
525 .WillByDefault(Return(std::vector<uint16_t>{1, 7}));
528 RegCont expected_write_reg {1, 5, 4};
529 WriteModbusRegister reg_write_srv;
530 reg_write_srv.request.holding_register_block.start_idx = 3;
531 reg_write_srv.request.holding_register_block.values = expected_write_reg;
533 RegCont expected_read_reg {14, 17};
535 EXPECT_CALL( *mock, writeReadHoldingRegister(static_cast<int>(reg_write_srv.request.holding_register_block.start_idx),
538 static_cast<int>(expected_read_reg.size())) )
540 .WillOnce(DoAll(ACTION_OPEN_BARRIER_VOID(
"writeHoldingRegister"), Return(expected_read_reg)));
542 EXPECT_CALL(*
this, modbus_read_cb(_))
545 EXPECT_CALL(*
this, modbus_read_cb(IsSuccessfullRead(expected_read_reg)))
548 std::vector<unsigned short> registers(expected_read_reg.size());
551 auto modbus_client = std::make_shared< PilzModbusClient >(nh_, registers, std::move(mock),
562 EXPECT_TRUE(modbus_client->isRunning()) <<
"Modbus client not running";
564 EXPECT_TRUE(writer_client.call(reg_write_srv)) <<
"Modbus write service failed";
565 EXPECT_TRUE(reg_write_srv.response.success) <<
"Modbus write service could not write modbus register";
567 BARRIER(
"writeHoldingRegister");
570 EXPECT_FALSE(modbus_client->isRunning());
579 std::vector<unsigned short> in_throw = {1, 2, 1};
584 std::vector<unsigned short> in_split = {1, 2, 4, 5};
586 std::vector<std::vector<unsigned short>> expected_out_split = {{1, 2}, {4, 5}};
587 EXPECT_EQ(out_split, expected_out_split);
590 std::vector<unsigned short> in_nosplit = {1, 2, 3};
592 std::vector<std::vector<unsigned short>> expected_out_nosplit = {{1, 2, 3}};
593 EXPECT_EQ(out_nosplit, expected_out_nosplit);
597 int main(
int argc,
char *argv[])
599 ros::init(argc, argv,
"pilz_modbus_client_test");
602 testing::InitGoogleTest(&argc, argv);
603 return RUN_ALL_TESTS();
HoldingRegisterIncreaser(unsigned int register_index=0u)
void run()
Publishes the register values as messages.
ros::Subscriber subscriber_
std::vector< uint16_t > RegCont
Convenience data type defining the data type for a collection of registers.
int main(int argc, char *argv[])
Expection thrown by prbt_hardware_support::PilzModbusClient.
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
static constexpr unsigned int REGISTER_FIRST_IDX_TEST
void callbackDummy(const ModbusMsgInStampedConstPtr &)
PilzModbusClientExecutor(PilzModbusClient *client)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
MATCHER_P(IsSuccessfullRead, vec,"")
static const std::string SERVICE_MODBUS_WRITE
std::thread client_thread_
static constexpr double WAIT_FOR_START_TIMEOUT_S
static constexpr unsigned int REGISTER_SIZE_TEST
bool isRunning()
True if 'run()' method is active, false if 'run()' method is not active or, currently, finishing.
static constexpr double WAIT_SLEEPTIME_S
Test if PilzModbusClient correctly publishes ROS-Modbus messages.
static const std::string TOPIC_MODBUS_READ
static constexpr double WAIT_FOR_STOP_TIMEOUT_S
static constexpr double WAIT_FOR_SERVICE_TIMEOUT_S
Mock used in the unittest of the PilzModbusClient.
TEST_F(LibModbusClientTest, testModbusClientDtor)
Test increases function coverage by ensuring that all Dtor variants are called.
uint32_t getNumPublishers() const
Connects to a modbus server and publishes the received data into ROS.
Strictly increases the holding register each time the "readHoldingRegister" method is called...
PilzModbusClient * client_
Helper class to simplify the threading of the PilzModbusClient.
void add(ModbusMsgInStamped msg)
static constexpr unsigned int DEFAULT_MODBUS_PORT_TEST
const unsigned int register_index_
static std::vector< std::vector< unsigned short > > split_into_blocks(std::vector< unsigned short > &in)
Splits a vector of integers into a vector of vectors with consecutive groups.
RegCont readHoldingRegister(int, int nb)
constexpr const char *const LOCALHOST
Expection thrown by prbt_hardware_support::LibModbusClient::readHoldingRegister if a disconnect from ...
void terminate()
Ends the infinite loop started in method 'run()'.
static constexpr unsigned int RESPONSE_TIMEOUT