75 : m_ip_port_results(ip_port_results), m_ip_port_cola(ip_port_cola), m_ioservice(),
76 m_tcp_connection_thread_results(0), m_tcp_connection_thread_cola(0), m_tcp_send_scandata_thread(0),
77 m_tcp_connection_thread_running(false), m_worker_thread_running(false), m_tcp_send_scandata_thread_running(false),
78 m_tcp_acceptor_results(m_ioservice,
boost::asio::ip::tcp::endpoint(
boost::asio::ip::tcp::v4(), m_ip_port_results)),
79 m_tcp_acceptor_cola(m_ioservice,
boost::asio::ip::tcp::endpoint(
boost::asio::ip::tcp::v4(), m_ip_port_cola)),
80 m_start_scandata_delay(1), m_result_telegram_rate(10), m_demo_move_in_circles(false), m_error_simulation_enabled(false), m_error_simulation_flag(
NO_ERROR),
81 m_error_simulation_thread(0), m_error_simulation_thread_running(false)
92 std::string result_testcases_topic =
"/sick_scan/test_server/result_testcases";
94 ROS::param<std::string>(nh,
"/sick_scan/test_server/result_testcases_topic", result_testcases_topic, result_testcases_topic);
98 std::string sim_loc_test_server_demo_circles, sim_loc_test_server_error_simulation;
99 ROS::param<std::string>(nh,
"/system/test_server/demo_circles", sim_loc_test_server_demo_circles, sim_loc_test_server_demo_circles);
100 ROS::param<std::string>(nh,
"/system/test_server/error_simulation", sim_loc_test_server_error_simulation, sim_loc_test_server_error_simulation);
101 if(!sim_loc_test_server_demo_circles.empty())
102 m_demo_move_in_circles = std::atoi(sim_loc_test_server_demo_circles.c_str()) > 0;
103 if(!sim_loc_test_server_error_simulation.empty())
104 m_error_simulation_enabled = std::atoi(sim_loc_test_server_error_simulation.c_str()) > 0;
126 ROS_WARN_STREAM(
"TestServerThread: running in error simulation mode.");
127 ROS_WARN_STREAM(
"Test server will intentionally react incorrect and will send false data and produce communication errors.");
128 ROS_WARN_STREAM(
"Running test server in error simulation mode is for test purposes only. Do not expect typical results.");
134 ROS_INFO_STREAM(
"TestServerThread: running in demo mode (moving in circles, no error simulation).");
138 ROS_INFO_STREAM(
"TestServerThread: running in normal mode (no error simulation).");
165 for(std::vector<boost::asio::ip::tcp::acceptor*>::iterator iter_acceptor = tcp_acceptors.begin(); iter_acceptor != tcp_acceptors.end(); iter_acceptor++)
167 if((*iter_acceptor)->is_open())
169 (*iter_acceptor)->cancel();
170 (*iter_acceptor)->close();
175 for(std::vector<thread_ptr*>::iterator iter_connection_thread = tcp_connection_threads.begin(); iter_connection_thread != tcp_connection_threads.end(); iter_connection_thread++)
177 thread_ptr & tcp_connection_thread = **iter_connection_thread;
178 if(tcp_connection_thread)
180 tcp_connection_thread->join();
181 delete(tcp_connection_thread);
182 tcp_connection_thread = 0;
214 for(std::list<boost::asio::ip::tcp::socket*>::iterator socket_iter =
m_tcp_sockets.begin(); socket_iter !=
m_tcp_sockets.end(); socket_iter++)
216 boost::asio::ip::tcp::socket* p_socket = *socket_iter;
219 if(p_socket && (force_shutdown || p_socket->is_open()))
221 p_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
225 catch(std::exception & exc)
227 ROS_WARN_STREAM(
"TestServerThread::closeTcpConnections(): exception " << exc.what() <<
" on closing socket.");
243 if(p_socket && p_socket->is_open())
245 p_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
250 for(std::list<boost::asio::ip::tcp::socket*>::iterator socket_iter =
m_tcp_sockets.begin(); socket_iter !=
m_tcp_sockets.end(); )
252 if(p_socket == *socket_iter)
260 catch(std::exception & exc)
262 ROS_WARN_STREAM(
"TestServerThread::closeSocket(): exception " << exc.what() <<
" on closing socket.");
275 boost::thread *p_thread = *thread_iter;
325 boost::asio::ip::tcp::socket* tcp_client_socket =
new boost::asio::ip::tcp::socket(
m_ioservice);
326 boost::system::error_code errorcode;
328 ROS_INFO_STREAM(
"TestServerThread: listening to tcp connections on port " << ip_port_results);
329 tcp_acceptor_results.listen();
335 tcp_acceptor_results.accept(*tcp_client_socket, errorcode);
338 if(tcp_client_socket->is_open())
340 tcp_client_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
341 tcp_client_socket->close();
346 if (!errorcode && tcp_client_socket->is_open())
349 ROS_INFO_STREAM(
"TestServerThread: established new tcp client connection");
368 ROS_INFO_STREAM(
"TestServerThread: worker thread for result telegrams started");
372 double circle_yaw = 0;
376 boost::system::error_code error_code;
379 ROS_DEBUG_STREAM(
"TestServerThread for cresult telegrams: error simulation, server not sending any telegrams");
384 std::vector<uint8_t> random_data = random_generator.
generate(random_length.
generate());
385 boost::asio::write(*p_socket, boost::asio::buffer(random_data.data(), random_data.size()), boost::asio::transfer_exactly(random_data.size()), error_code);
398 int number_random_bytes = ((random_integer.
generate()) % (testcase.binary_data.size()));
399 for(
int cnt_random_bytes = 0; cnt_random_bytes < number_random_bytes; cnt_random_bytes++)
401 int byte_cnt = ((random_integer.
generate()) % (testcase.binary_data.size()));
402 testcase.binary_data[byte_cnt] = (uint8_t)(random_generator.
generate() & 0xFF);
409 size_t bytes_written = boost::asio::write(*p_socket, boost::asio::buffer(testcase.binary_data.data(), testcase.binary_data.size()), boost::asio::transfer_exactly(testcase.binary_data.size()), error_code);
410 if (error_code || bytes_written != testcase.binary_data.size())
412 std::stringstream error_info;
413 error_info <<
"## ERROR TestServerThread for result telegrams: failed to send binary result port telegram, " << bytes_written <<
" of " << testcase.binary_data.size() <<
" bytes send, error code: " << error_code.message();
416 ROS_WARN_STREAM(error_info.str() <<
", close socket and leave worker thread for result telegrams");
432 ROS_INFO_STREAM(
"TestServerThread: worker thread for result telegrams finished");
443 ROS_INFO_STREAM(
"TestServerThread: worker thread for command requests started");
444 int iTransmitErrorCnt = 0;
452 ROS::Time receive_timestamp;
457 ROS_DEBUG_STREAM(
"TestServerThread for command requests: error simulation, server not sending any telegrams");
462 boost::system::error_code error_code;
463 std::vector<uint8_t> random_data = random_generator.
generate(random_length.
generate());
464 boost::asio::write(*p_socket, boost::asio::buffer(random_data.data(), random_data.size()), boost::asio::transfer_exactly(random_data.size()), error_code);
473 ROS_INFO_STREAM(
"TestServerThread: received cola request " << ascii_telegram);
479 telegram_answer.command_name = random_ascii.
generate(random_length.
generate());
480 telegram_answer.parameter.clear();
481 for(
int n = random_length.
generate(); n > 0; n--)
482 telegram_answer.parameter.push_back(random_ascii.
generate(random_length.
generate()));
489 ROS_INFO_STREAM(
"TestServerThread: sending cola response " << ascii_response << (cola_binary ?
" (Cola-Binary)" :
" (Cola-ASCII)"));
493 ROS::Time send_timestamp;
498 if(iTransmitErrorCnt >= 10)
500 ROS_WARN_STREAM(
"## ERROR TestServerThread: " << iTransmitErrorCnt <<
" transmission errors, giving up.");
501 ROS_WARN_STREAM(
"## ERROR TestServerThread: shutdown after error, aborting");
507 iTransmitErrorCnt = 0;
526 ROS_INFO_STREAM(
"TestServerThread: worker thread for command requests finished");
537 std::vector<sick_scan::JsonScanData> binary_messages;
538 ROS_INFO_STREAM(
"TestServerThread: worker thread sending scandata and scandatamon messages started.");
541 ROS_WARN_STREAM(
"## WARNING TestServerThread::runWorkerThreadScandataCb(): no scandata files configured, aborting worker thread to send scandata.");
551 for(
int n = 0; n < scandatafiles.size(); n++)
555 ROS_WARN_STREAM(
"## WARNING TestServerThread: error reading file \"" << scandatafiles[n] <<
"\".");
559 ROS_INFO_STREAM(
"TestServerThread: file \"" << scandatafiles[n] <<
"\" successfully parsed, " << binary_messages.size() <<
" messages of types \"" <<
m_scandatatypes <<
"\".");
560 start_timestamp = binary_messages.back().timestamp + 0.01;
564 if(binary_messages.empty())
566 ROS_WARN_STREAM(
"## WARNING TestServerThread::runWorkerThreadScandataCb(): no scandata found, aborting worker thread to send scandata.");
571 double last_msg_timestamp = 0;
572 int iTransmitErrorCnt = 0;
575 if(msg_cnt >= (
int)binary_messages.size())
577 msg_cnt = (int)binary_messages.size() - 2;
582 msg_cnt = std::min(1, (
int)binary_messages.size() - 1);
589 ROS_INFO_STREAM(
"TestServerThread: sending " << binary_message.
data.size() <<
" byte scan data " 591 ROS::Time send_timestamp =
ROS::now();
596 if(iTransmitErrorCnt >= 10)
598 ROS_WARN_STREAM(
"## ERROR TestServerThread: " << iTransmitErrorCnt <<
" transmission errors, giving up.");
599 ROS_WARN_STREAM(
"## ERROR TestServerThread: shutdown after error, aborting");
605 iTransmitErrorCnt = 0;
607 last_msg_timestamp = binary_message.
timestamp;
611 ROS_INFO_STREAM(
"TestServerThread: worker thread sending scandata and scandatamon messages finished.");
653 sick_scan::SickLocResultPortTelegramMsg telegram_msg;
654 size_t number_testcases = 0, number_testcases_failed = 0;
660 ROS_INFO_STREAM(
"TestServerThread: 1. error simulation testcase: normal execution, expecting telegram messages from driver");
664 number_testcases_failed++;
665 ROS_WARN_STREAM(
"## ERROR TestServerThread: 1. error simulation testcase: no ros telegram message received, expected SickLocResultPortTelegramMsg from driver");
673 ROS_INFO_STREAM(
"TestServerThread: 2. error simulation testcase: server not responding, not listening, no tcp connections accepted.");
679 ROS_INFO_STREAM(
"TestServerThread: 2. error simulation testcase: switched to normal execution, expecting telegram messages from driver");
683 number_testcases_failed++;
684 ROS_WARN_STREAM(
"## ERROR TestServerThread: 2. error simulation testcase: no ros telegram message received, expected SickLocResultPortTelegramMsg from driver");
692 ROS_INFO_STREAM(
"TestServerThread: 3. error simulation testcase: server not responding, listening on port " <<
m_ip_port_results <<
", but accepting no tcp clients");
701 number_testcases_failed++;
702 ROS_WARN_STREAM(
"## ERROR TestServerThread: 3. error simulation testcase: no ros telegram message received, expected SickLocResultPortTelegramMsg from driver");
710 ROS_INFO_STREAM(
"TestServerThread: 4. error simulation testcase: server not sending telegrams");
716 number_testcases_failed++;
717 ROS_WARN_STREAM(
"## ERROR TestServerThread: 4. error simulation testcase: no ros telegram message received, expected SickLocResultPortTelegramMsg from driver");
725 ROS_INFO_STREAM(
"TestServerThread: 5. error simulation testcase: server sending random tcp data");
731 number_testcases_failed++;
732 ROS_WARN_STREAM(
"## ERROR TestServerThread: 5. error simulation testcase: no ros telegram message received, expected SickLocResultPortTelegramMsg from driver");
740 ROS_INFO_STREAM(
"TestServerThread: 6. error simulation testcase: server sending invalid telegrams");
746 number_testcases_failed++;
747 ROS_WARN_STREAM(
"## ERROR TestServerThread: 6. error simulation testcase: no ros telegram message received, expected SickLocResultPortTelegramMsg from driver");
755 ROS_INFO_STREAM(
"TestServerThread: error simulation summary: " << (number_testcases - number_testcases_failed) <<
" of " << number_testcases<<
" testcases passed, " << number_testcases_failed <<
" failures.");
Default: run test server without simulated errors, send valid telegrams.
static double normalizeAngle(double angle)
virtual void runErrorSimulationThreadCb(void)
static std::vector< uint8_t > encodeColaTelegram(const sick_scan::SickLocColaTelegramMsg &cola_telegram, bool parameter_is_ascii=true)
Encodes and returns a Cola Binary telegram from ros message SickLocColaTelegramMsg.
static std::string flattenToString(const T &x)
void errorSimulationWait(double seconds)
virtual void runWorkerThreadResultCb(boost::asio::ip::tcp::socket *p_socket)
bool errorSimulationWaitForTelegramReceived(double timeout_seconds, sick_scan::SickLocResultPortTelegramMsg &telegram_msg)
void closeSocket(socket_ptr &p_socket)
static bool ResultTelegramsEnabled(void)
int m_ip_port_results
ip port for result telegrams, default: The localization controller uses IP port number 2201 to send l...
void closeScandataThread(void)
boost::asio::ip::tcp::acceptor m_tcp_acceptor_cola
boost acceptor for tcp clients for command requests and responses
static sick_scan::SickLocColaTelegramMsg createColaResponse(const sick_scan::SickLocColaTelegramMsg &cola_request, const std::string &scanner_type)
class JsonScanData: utility container for binary scandata incl. timestamp
boost::mutex m_tcp_worker_threads_mutex
mutex to protect m_tcp_worker_threads
static std::string toAsciiString(const uint8_t *binary_data, int length)
virtual void runConnectionThreadColaCb(void)
boost::asio::ip::tcp::socket * socket_ptr
shortcut for pointer to boost::asio::ip::tcp::socket
static uint32_t ResultPoseInterval(void)
virtual void closeTcpConnections(bool force_shutdown=false)
thread_ptr m_tcp_connection_thread_results
thread to accept tcp clients for result port telegrams
bool m_tcp_send_scandata_thread_running
true: m_tcp_send_scandata_thread is running, otherwise false
static std::string toHexString(const std::vector< uint8_t > &binary_data)
thread_ptr m_error_simulation_thread
thread to run error simulation, switches m_error_simulation_flag through the error test cases ...
Testserver sends invalid telegrams (invalid data, false checksums, etc.)
sick_scan::SetGet< ERROR_SIMULATION_FLAG > m_error_simulation_flag
current error simulation flag, default: NO_ERROR
Testserver does not send any data.
sick_scan::SickLocResultPortTestcaseMsgPublisher m_result_testcases_publisher
ros publisher for testcases with result port telegrams (type SickLocResultPortTestcaseMsg) ...
void runConnectionThreadGenericCb(boost::asio::ip::tcp::acceptor &tcp_acceptor_results, int ip_port_results, Callable thread_function_cb)
static sick_scan::SickLocColaTelegramMsg decodeColaTelegram(const std::vector< uint8_t > &cola_binary)
Decodes and returns a Cola message of type SickLocColaTelegramMsg from a Cola-Binary telegram...
thread_ptr m_tcp_send_scandata_thread
thread to send scandata and scandatamon tcp messages
static bool IsColaBinary(const std::vector< uint8_t > &cola_telegram)
Returns true for Cola-Binary, if a given telegram is Cola-Binary encoded and starts with 4 Bytes { 0x...
Testserver sends invalid random tcp packets.
TestServerThread(ROS::NodePtr nh=0, int ip_port_results=2201, int ip_port_cola=2111)
sick_scan::SetGet< sick_scan::SickLocResultPortTelegramMsg > m_last_telegram_received
last telegram message received from sick_scan driver
std::list< thread_ptr > m_tcp_worker_threads
list of tcp worker thread (one thread for each tcp client, generating telegrams)
static bool SendScandataEnabled(void)
std::string m_scandatafiles
comma separated list of jsonfiles to emulate scandata messages, f.e. "tim781s_scandata.pcapng.json,tim781s_sopas.pcapng.json"
std::vector< uint8_t > data
boost::thread * thread_ptr
shortcut for pointer to boost::thread
Testserver does not open listening port.
virtual void runWorkerThreadScandataCb(boost::asio::ip::tcp::socket *p_socket)
static bool parseJsonfile(const std::string &json_filename, const std::vector< std::string > &scandatatypes, double start_time, std::vector< sick_scan::JsonScanData > &scandata)
Parses a jsonfile and returns a list of binary scandata messages of given type.
void closeWorkerThreads(void)
std::list< boost::asio::ip::tcp::socket * > m_tcp_sockets
list of tcp sockets (one socket for each tcp client)
std::string m_scanner_type
currently supported: "sick_lms_5xx", "sick_tim_7xx"
virtual bool send(const std::vector< uint8_t > &data, ROS::Time &send_timestamp)
bool m_demo_move_in_circles
true: simulate a sensor moving in circles, false (default): create random based result port telegrams...
bool m_error_simulation_thread_running
true: m_error_simulation_thread is running, otherwise false
Testserver does not accecpt tcp clients.
double m_start_scandata_delay
delay between scandata activation ("LMCstartmeas" request) and first scandata message, default: 1 second
#define ROS_WARN_STREAM(args)
ROS::Time timeFromHeader(const std_msgs::Header *msg_header)
#define ROS_DEBUG_STREAM(args)
static std::vector< uint8_t > ColaBinaryToColaAscii(const std::vector< uint8_t > &cola_telegram, bool parameter_to_ascii=true)
Converts and returns a Cola telegram from Cola-ASCII to Cola-Binary.
virtual void runConnectionThreadResultCb(void)
thread_ptr m_tcp_connection_thread_cola
thread to accept tcp clients for command requests and responses
virtual void runWorkerThreadColaCb(boost::asio::ip::tcp::socket *p_socket)
#define ROS_INFO_STREAM(args)
static std::string ConvertColaAscii(const std::vector< uint8_t > &cola_telegram)
Converts and returns a Cola-ASCII telegram to string.
std::string m_scandatatypes
comma separated list of scandata message types, f.e. "sSN LMDscandata,sSN LMDscandatamon" ...
boost::asio::io_service m_ioservice
boost io service for tcp connections
int m_ip_port_cola
ip port for for command requests and responses, default: The localization controller uses IP port num...
static bool LocalizationEnabled(void)
static std::vector< std::string > split(const std::string &s, char delimiter)
Splits a comma separated string into its parts.
virtual bool receive(std::vector< uint8_t > &telegram, double timeout, ROS::Time &receive_timestamp)
std::vector< uint8_t > telegram_data
received telegram_data (Cola-Ascii or Cola-Binary)
void set(const ElementType &value)
bool m_error_simulation_enabled
default: false (no error simulation), if true, test server simulates errors and communication failure...
static std::vector< uint8_t > ColaTelegramToColaBinary(const sick_scan::SickLocColaTelegramMsg &cola_telegram, int parameter_is_ascii=-1)
Converts and returns a Cola telegram to Cola-Binary.
bool m_tcp_connection_thread_running
true: m_tcp_connection_thread is running, otherwise false
static sick_scan::SickLocResultPortTestcaseMsg createRandomResultPortTestcase(void)
virtual ~TestServerThread()
void messageCbResultPortTelegrams(const sick_scan::SickLocResultPortTelegramMsg &msg)
void sleep(double seconds)
bool m_worker_thread_running
true: worker threads started, otherwise false
double m_result_telegram_rate
frequency to generate and send result port telegrams, default: 10 Hz
std::string m_result_testcases_frame_id
ros frame id of testcase messages (type SickLocResultPortTestcaseMsg), default: "result_testcases" ...
double seconds(ROS::Duration duration)
static sick_scan::SickLocResultPortTestcaseMsg createResultPortCircles(double circle_radius, double circle_yaw)
boost::asio::ip::tcp::acceptor m_tcp_acceptor_results
boost acceptor for tcp clients for result telegrams