mirror of
https://github.com/wjwwood/serial.git
synced 2026-01-22 19:54:57 +08:00
Still working on SerialListener addition.
This commit is contained in:
parent
313b01985a
commit
318bce46bf
@ -1,4 +1,4 @@
|
|||||||
find_path(serial_INCLUDE_DIRS serial.h /usr/include "$ENV{NAMER_ROOT}")
|
find_path(serial_INCLUDE_DIRS serial.h serial_listener.h /usr/include/serial "$ENV{NAMER_ROOT}")
|
||||||
|
|
||||||
find_library(serial_LIBRARIES serial /usr/lib "$ENV{NAMER_ROOT}")
|
find_library(serial_LIBRARIES serial /usr/lib "$ENV{NAMER_ROOT}")
|
||||||
|
|
||||||
|
|||||||
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
|||||||
ifdef ROS_ROOT
|
ifdef ROS_ROOT
|
||||||
include $(shell rospack find mk)/cmake.mk
|
include $(shell rospack find mk)/cmake.mk
|
||||||
else
|
else
|
||||||
include serial.mk
|
include serial.makefile
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -25,14 +25,14 @@ int main(void) {
|
|||||||
SerialListener listener;
|
SerialListener listener;
|
||||||
// Set the time to live for messages to 1 second
|
// Set the time to live for messages to 1 second
|
||||||
listener.setTimeToLive(1000);
|
listener.setTimeToLive(1000);
|
||||||
listener.startListening(serial);
|
listener.startListening(&serial);
|
||||||
|
|
||||||
listener.listenFor(comparator, callback);
|
listener.listenFor(comparator, callback);
|
||||||
|
|
||||||
serial.write("?$1E\r");
|
serial.write("?$1E\r");
|
||||||
if (!listener.listenForOnce("?$1E")) {
|
if (!listener.listenForStringOnce("?$1E")) {
|
||||||
std::cerr << "Didn't get conformation of device version!" << std::endl;
|
std::cerr << "Didn't get conformation of device version!" << std::endl;
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef SERIAL_LISTENER_H
|
||||||
|
#define SERIAL_LISTENER_H
|
||||||
|
|
||||||
// Serial
|
// Serial
|
||||||
#include <serial/serial.h>
|
#include <serial/serial.h>
|
||||||
|
|
||||||
@ -43,14 +46,10 @@
|
|||||||
#include <boost/uuid/uuid_generators.hpp>
|
#include <boost/uuid/uuid_generators.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
|
||||||
#ifndef SERIAL_LISTENER_TEST
|
|
||||||
#define SERIAL_LISTENER_TEST false
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace serial {
|
namespace serial {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* This is a general function type that is used both as the callback prototype
|
* This is a general function type that is used as the callback prototype
|
||||||
* for asynchronous functions like the default handler callback and the
|
* for asynchronous functions like the default handler callback and the
|
||||||
* listenFor callbacks.
|
* listenFor callbacks.
|
||||||
*
|
*
|
||||||
@ -60,7 +59,7 @@ namespace serial {
|
|||||||
*
|
*
|
||||||
* \see SerialListener::listenFor, SerialListener::setDefaultHandler
|
* \see SerialListener::listenFor, SerialListener::setDefaultHandler
|
||||||
*/
|
*/
|
||||||
typedef boost::function<void(const std::string&)> SerialCallback;
|
typedef boost::function<void(const std::string&)> DataCallback;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* This is a general function type that is used as the comparator callback
|
* This is a general function type that is used as the comparator callback
|
||||||
@ -74,22 +73,101 @@ typedef boost::function<void(const std::string&)> SerialCallback;
|
|||||||
*/
|
*/
|
||||||
typedef boost::function<bool(const std::string&)> ComparatorType;
|
typedef boost::function<bool(const std::string&)> ComparatorType;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This function type describes the prototype for the logging callbacks.
|
||||||
|
*
|
||||||
|
* The function takes a std::string reference and returns nothing. It is
|
||||||
|
* called from the library when a logging message occurs. This
|
||||||
|
* allows the library user to hook into this and integrate it with their own
|
||||||
|
* logging system. It can be set with any of the set<log level>Handler
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* \see SerialListener::setInfoHandler, SerialListener::setDebugHandler,
|
||||||
|
* SerialListener::setWarningHandler
|
||||||
|
*/
|
||||||
|
typedef boost::function<void(const std::string&)> LoggingCallback;
|
||||||
|
|
||||||
typedef boost::function<void(const std::string&)> InfoCallback;
|
/*!
|
||||||
typedef boost::function<void(const std::string&)> WarningCallback;
|
* This function type describes the prototype for the exception callback.
|
||||||
typedef boost::function<void(const std::string&)> DebugCallback;
|
*
|
||||||
|
* The function takes a std::exception reference and returns nothing. It is
|
||||||
|
* called from the library when an exception occurs in a library thread.
|
||||||
|
* This exposes these exceptions to the user so they can to error handling.
|
||||||
|
*
|
||||||
|
* \see SerialListener::setExceptionHandler
|
||||||
|
*/
|
||||||
typedef boost::function<void(const std::exception&)> ExceptionCallback;
|
typedef boost::function<void(const std::exception&)> ExceptionCallback;
|
||||||
|
|
||||||
typedef boost::uuids::uuid uuid_t;
|
/*!
|
||||||
|
* This function type describes the prototype for the tokenizer callback.
|
||||||
|
*
|
||||||
|
* The function should take a std::string reference and tokenize it into a
|
||||||
|
* several std::string's and store them in the given
|
||||||
|
* std::vector<std::string> reference. There are some default ones or the
|
||||||
|
* user can create their own.
|
||||||
|
*
|
||||||
|
* The last element in the std::vector of std::string's should always be
|
||||||
|
* either an empty string ("") or the last partial message. The last element
|
||||||
|
* in the std::vector will be put back into the data buffer so that if it is
|
||||||
|
* incomplete it can be completed when more data is read.
|
||||||
|
*
|
||||||
|
* Example: A delimeter tokenizer with a delimeter of "\r". The result would
|
||||||
|
* be: "msg1\rmsg2\r" -> ["msg1", "msg2", ""] for all complete messages, or:
|
||||||
|
* "msg1\rpartial_msg2" -> ["msg1","partial_msg2"] for partial messages.
|
||||||
|
*
|
||||||
|
* \see SerialListener::setTokenizer, serial::delimeter_tokenizer
|
||||||
|
*/
|
||||||
|
typedef boost::function<void(std::string&,std::vector<std::string>&)>
|
||||||
|
TokenizerType;
|
||||||
|
|
||||||
class SerialListenerException : public std::exception {
|
/*! This is a convenience alias for boost::uuids::uuid. */
|
||||||
const char * e_what;
|
typedef boost::uuids::uuid uuid_type; // uuid_t is already taken! =(
|
||||||
|
|
||||||
|
void
|
||||||
|
_delimeter_tokenizer (std::string &data, std::vector<std::string> &tokens,
|
||||||
|
std::string delimeter);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This returns a tokenizer that splits on a given delimeter.
|
||||||
|
*
|
||||||
|
* The delimeter is passed into the function and a TokenizerType is returned
|
||||||
|
* that can be passed to SerialListener::setTokenizer.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* <pre>
|
||||||
|
* my_listener.setTokenizer(delimeter_tokenizer("\r"));
|
||||||
|
* <\pre>
|
||||||
|
*
|
||||||
|
* \see SerialListener::setTokenizer, serial::TokenizerType
|
||||||
|
*/
|
||||||
|
class delimeter_tokenizer
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
SerialListenerException(const char * e_what) {this->e_what = e_what;}
|
delimeter_tokenizer ();
|
||||||
|
virtual ~delimeter_tokenizer ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
};
|
||||||
|
TokenizerType
|
||||||
|
delimeter_tokenizer (std::string delimeter);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is a general exception generated by the SerialListener class.
|
||||||
|
*
|
||||||
|
* Check the SerialListenerException::what function for the cause.
|
||||||
|
|
||||||
|
* \param e_what is a std::string that describes the cause of the error.
|
||||||
|
*/
|
||||||
|
class SerialListenerException : public std::exception {
|
||||||
|
const std::string e_what;
|
||||||
|
public:
|
||||||
|
SerialListenerException(const std::string e_what) : e_what(e_what) {}
|
||||||
|
~SerialListenerException() throw() {std::exception::~exception();}
|
||||||
|
|
||||||
virtual const char* what() const throw() {
|
virtual const char* what() const throw() {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Error listening to serial port: " << this->e_what;
|
ss << "SerialListenerException: " << this->e_what;
|
||||||
return ss.str().c_str();
|
return ss.str().c_str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -110,12 +188,36 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ~SerialListener ();
|
virtual ~SerialListener ();
|
||||||
|
|
||||||
|
/***** Configurations ******/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sets the time-to-live (ttl) for messages waiting to be processsed.
|
* Sets the time-to-live (ttl) for messages waiting to be processsed.
|
||||||
*
|
*
|
||||||
|
* Messages are processed before checking for expiration, therefore they
|
||||||
|
* will always be passed through filters once before being removed
|
||||||
|
* due to ttl expiration. The default value for this is 10 ms.
|
||||||
|
*
|
||||||
* \param ms Time in milliseconds until messages are purged from the buffer.
|
* \param ms Time in milliseconds until messages are purged from the buffer.
|
||||||
*/
|
*/
|
||||||
void setTimeToLive (size_t ms);
|
void setTimeToLive (size_t ms = 10);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the tokenizer to be used when tokenizing the data into tokens.
|
||||||
|
*
|
||||||
|
* This function is given a std::string of data and is responsible for
|
||||||
|
* tokenizing that data into a std::vector<std::string> of data tokens.
|
||||||
|
* The default tokenizer splits the data by the ascii return carriage.
|
||||||
|
* The user can create their own tokenizer or use one of the default ones.
|
||||||
|
*
|
||||||
|
* \param tokenizer Function for tokenizing the incoming data.
|
||||||
|
*
|
||||||
|
* \see serial::TokenizerType, serial::delimeter_tokenizer
|
||||||
|
*/
|
||||||
|
void setTokenizer (TokenizerType tokenizer) {
|
||||||
|
this->tokenize = tokenizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Start and Stop Listening ******/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Starts a thread to listen for messages and process them through filters.
|
* Starts a thread to listen for messages and process them through filters.
|
||||||
@ -127,9 +229,14 @@ public:
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Stops the listening thread and blocks until it completely stops.
|
* Stops the listening thread and blocks until it completely stops.
|
||||||
|
*
|
||||||
|
* This function also clears all of the active filters from listenFor and
|
||||||
|
* similar functions.
|
||||||
*/
|
*/
|
||||||
void stopListening ();
|
void stopListening ();
|
||||||
|
|
||||||
|
/***** Filter Functions ******/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Blocks until the given string is detected or until the timeout occurs.
|
* Blocks until the given string is detected or until the timeout occurs.
|
||||||
*
|
*
|
||||||
@ -144,51 +251,198 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool listenForStringOnce (std::string token, size_t timeout = 1000);
|
bool listenForStringOnce (std::string token, size_t timeout = 1000);
|
||||||
|
|
||||||
boost::uuids::uuid listenFor (ComparatorType, SerialCallback);
|
/*!
|
||||||
void stopListeningFor (boost::uuids::uuid filter_uuid);
|
* Setups up a filter that calls a callback when a comparator returns true.
|
||||||
|
*
|
||||||
|
* The user provides a comparator and a callback, and every time a line is
|
||||||
|
* received the comparator is called and the comparator has to evaluate the
|
||||||
|
* line and return true if it matches and false if it doesn't. If it does
|
||||||
|
* match, the callback is called with the resulting line.
|
||||||
|
*
|
||||||
|
* \param comparator This is a comparator for detecting if a line matches.
|
||||||
|
* The comparartor receives a std::string reference and must return a true
|
||||||
|
* if it matches and false if it doesn't.
|
||||||
|
*
|
||||||
|
* \param callback This is the handler for when a match occurs. It is given
|
||||||
|
* a std::string reference of the line that matched your comparator.
|
||||||
|
*
|
||||||
|
* \return boost::uuids::uuid a unique identifier used to remove the filter.
|
||||||
|
*/
|
||||||
|
uuid_type listenFor (ComparatorType comparator, DataCallback callback);
|
||||||
|
|
||||||
InfoCallback info;
|
/*!
|
||||||
WarningCallback warn;
|
* Removes a filter by a given uuid.
|
||||||
DebugCallback debug;
|
*
|
||||||
ExceptionCallback handle_exc;
|
* The uuid for a filter is returned by the listenFor function.
|
||||||
SerialCallback default_handler;
|
*
|
||||||
|
* \param filter_uuid The uuid of the filter to be removed.
|
||||||
|
*/
|
||||||
|
void stopListeningFor (uuid_type filter_uuid);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Stops listening for anything, but doesn't stop reading the serial port.
|
||||||
|
*/
|
||||||
|
void stopListeningForAll ();
|
||||||
|
|
||||||
|
/***** Hooks and Handlers ******/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the handler to be called when a lines is not caught by a filter.
|
||||||
|
*
|
||||||
|
* This allows you to set a catch all function that will get called
|
||||||
|
* everytime a line is not matched by a filter and the ttl expires.
|
||||||
|
*
|
||||||
|
* Setting the callbacks works just like SerialListener::setInfoHandler.
|
||||||
|
*
|
||||||
|
* \param default_handler A function pointer to the callback to handle
|
||||||
|
* unmatched and expired messages.
|
||||||
|
*
|
||||||
|
* \see serial::DataCallback, SerialListener::setInfoHandler
|
||||||
|
*/
|
||||||
|
void setDefaultHandler(DataCallback default_handler) {
|
||||||
|
this->default_handler = default_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the function to be called when an info logging message occurs.
|
||||||
|
*
|
||||||
|
* This allows you to hook into the message reporting of the library and use
|
||||||
|
* your own logging facilities.
|
||||||
|
*
|
||||||
|
* The provided function must follow this prototype:
|
||||||
|
* <pre>
|
||||||
|
* void yourInfoCallback(const std::string &msg)
|
||||||
|
* </pre>
|
||||||
|
* Here is an example:
|
||||||
|
* <pre>
|
||||||
|
* void yourInfoCallback(const std::string &msg) {
|
||||||
|
* std::cout << "SerialListener Info: " << msg << std::endl;
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* And the resulting call to make it the callback:
|
||||||
|
* <pre>
|
||||||
|
* serial::SerialListener listener;
|
||||||
|
* listener.setInfoCallback(yourInfoCallback);
|
||||||
|
* </pre>
|
||||||
|
* Alternatively you can use a class method as a callback using boost::bind:
|
||||||
|
* <pre>
|
||||||
|
* #include <boost/bind.hpp>
|
||||||
|
*
|
||||||
|
* #include "serial/serial_listener.h"
|
||||||
|
*
|
||||||
|
* class MyClass
|
||||||
|
* {
|
||||||
|
* public:
|
||||||
|
* MyClass () {
|
||||||
|
* listener.setInfoHandler(
|
||||||
|
* boost::bind(&MyClass::handleInfo, this, _1));
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* void handleInfo(const std::string &msg) {
|
||||||
|
* std::cout << "MyClass Info: " << msg << std::endl;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* private:
|
||||||
|
* serial::SerialListener listener;
|
||||||
|
* };
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* \param info_handler A function pointer to the callback to handle new
|
||||||
|
* Info messages.
|
||||||
|
*
|
||||||
|
* \see serial::LoggingCallback
|
||||||
|
*/
|
||||||
|
void setInfoHandler(LoggingCallback info_handler) {
|
||||||
|
this->info = info_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the function to be called when a debug logging message occurs.
|
||||||
|
*
|
||||||
|
* This allows you to hook into the message reporting of the library and use
|
||||||
|
* your own logging facilities.
|
||||||
|
*
|
||||||
|
* This works just like SerialListener::setInfoHandler.
|
||||||
|
*
|
||||||
|
* \param debug_handler A function pointer to the callback to handle new
|
||||||
|
* Debug messages.
|
||||||
|
*
|
||||||
|
* \see serial::LoggingCallback, SerialListener::setInfoHandler
|
||||||
|
*/
|
||||||
|
void setDebugHandler(LoggingCallback debug_handler) {
|
||||||
|
this->debug = debug_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the function to be called when a warning logging message occurs.
|
||||||
|
*
|
||||||
|
* This allows you to hook into the message reporting of the library and use
|
||||||
|
* your own logging facilities.
|
||||||
|
*
|
||||||
|
* This works just like SerialListener::setInfoHandler.
|
||||||
|
*
|
||||||
|
* \param warning_handler A function pointer to the callback to handle new
|
||||||
|
* Warning messages.
|
||||||
|
*
|
||||||
|
* \see serial::LoggingCallback, SerialListener::setInfoHandler
|
||||||
|
*/
|
||||||
|
void setWarningHandler(LoggingCallback warning_handler) {
|
||||||
|
this->warn = warning_handler;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Function that loops while listening is true
|
||||||
void listen ();
|
void listen ();
|
||||||
|
// Called by listen iteratively
|
||||||
std::string listenOnce (std::string data);
|
std::string listenOnce (std::string data);
|
||||||
|
// Determines how much to read on each loop of listen
|
||||||
size_t determineAmountToRead ();
|
size_t determineAmountToRead ();
|
||||||
|
// Used in the look for string once function
|
||||||
bool listenForOnceComparator(std::string line);
|
bool listenForOnceComparator(std::string line);
|
||||||
|
|
||||||
|
// Tokenizer
|
||||||
|
TokenizerType tokenize;
|
||||||
|
|
||||||
|
// Logging handlers
|
||||||
|
LoggingCallback warn;
|
||||||
|
LoggingCallback info;
|
||||||
|
LoggingCallback debug;
|
||||||
|
|
||||||
|
// Exception handler
|
||||||
|
ExceptionCallback handle_exc;
|
||||||
|
|
||||||
|
// Default handler
|
||||||
|
DataCallback default_handler;
|
||||||
|
|
||||||
|
// Persistent listening variables
|
||||||
bool listening;
|
bool listening;
|
||||||
|
|
||||||
serial::Serial * serial_port;
|
serial::Serial * serial_port;
|
||||||
|
|
||||||
boost::thread listen_thread;
|
boost::thread listen_thread;
|
||||||
boost::uuids::random_generator random_generator();
|
|
||||||
|
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
std::map<const uuid_t,std::string> lines;
|
std::map<const uuid_type,std::string> lines;
|
||||||
std::map<const uuid_t,boost::posix_time::ptime> ttls;
|
std::map<const uuid_type,boost::posix_time::ptime> ttls;
|
||||||
|
|
||||||
|
// For generating random uuids
|
||||||
|
boost::uuids::random_generator random_generator;
|
||||||
|
|
||||||
|
// Setting for ttl on messages
|
||||||
boost::posix_time::time_duration ttl;
|
boost::posix_time::time_duration ttl;
|
||||||
|
|
||||||
// map<uuid, filter type (blocking/non-blocking)>
|
// map<uuid, filter type (blocking/non-blocking)>
|
||||||
std::map<const uuid_t,std::string> filters;
|
std::map<const uuid_type,std::string> filters;
|
||||||
// map<uuid, comparator>
|
// map<uuid, comparator>
|
||||||
std::map<const uuid_t,ComparatorType> comparators;
|
std::map<const uuid_type,ComparatorType> comparators;
|
||||||
// map<uuid, callback>
|
// map<uuid, callback>
|
||||||
std::map<const uuid_t,SerialCallback> callbacks;
|
std::map<const uuid_type,DataCallback> callbacks;
|
||||||
// map<uuid, conditional_variables>
|
// map<uuid, conditional_variables>
|
||||||
std::map<const uuid_t,boost::condition_variable*>
|
std::map<const uuid_type,boost::condition_variable*> condition_vars;
|
||||||
condition_vars;
|
// Mutex for locking use of filters
|
||||||
|
|
||||||
// ptime time_start(microsec_clock::local_time());
|
|
||||||
// //... execution goes here ...
|
|
||||||
// ptime time_end(microsec_clock::local_time());
|
|
||||||
// time_duration duration(time_end - time_start);
|
|
||||||
|
|
||||||
std::string current_listen_for_one_target;
|
|
||||||
|
|
||||||
boost::mutex filter_mux;
|
boost::mutex filter_mux;
|
||||||
|
|
||||||
|
// Used as temporary storage for listenForStringOnce
|
||||||
|
std::string current_listen_for_one_target;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // SERIAL_LISTENER_H
|
||||||
35
serial.cmake
35
serial.cmake
@ -10,6 +10,11 @@ project(Serial)
|
|||||||
|
|
||||||
## Configurations
|
## Configurations
|
||||||
|
|
||||||
|
# Use clang if available
|
||||||
|
IF(EXISTS /usr/bin/clang)
|
||||||
|
set(CMAKE_CXX_COMPILER /usr/bin/clang++)
|
||||||
|
ENDIF(EXISTS /usr/bin/clang)
|
||||||
|
|
||||||
option(SERIAL_BUILD_TESTS "Build all of the Serial tests." OFF)
|
option(SERIAL_BUILD_TESTS "Build all of the Serial tests." OFF)
|
||||||
option(SERIAL_BUILD_EXAMPLES "Build all of the Serial examples." OFF)
|
option(SERIAL_BUILD_EXAMPLES "Build all of the Serial examples." OFF)
|
||||||
|
|
||||||
@ -33,9 +38,9 @@ ENDIF(NOT DEFINED(LIBRARY_OUTPUT_PATH))
|
|||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
# Add default source files
|
# Add default source files
|
||||||
set(SERIAL_SRCS src/serial.cpp)
|
set(SERIAL_SRCS src/serial.cc src/serial_listener.cc)
|
||||||
# Add default header files
|
# Add default header files
|
||||||
set(SERIAL_HEADERS include/serial/serial.h)
|
set(SERIAL_HEADERS include/serial/serial.h include/serial/serial_listener.h)
|
||||||
|
|
||||||
# Find Boost, if it hasn't already been found
|
# Find Boost, if it hasn't already been found
|
||||||
IF(NOT Boost_FOUND OR NOT Boost_SYSTEM_FOUND OR NOT Boost_FILESYSTEM_FOUND OR NOT Boost_THREAD_FOUND)
|
IF(NOT Boost_FOUND OR NOT Boost_SYSTEM_FOUND OR NOT Boost_FILESYSTEM_FOUND OR NOT Boost_THREAD_FOUND)
|
||||||
@ -67,17 +72,33 @@ ENDIF(CMAKE_SYSTEM_NAME MATCHES Darwin)
|
|||||||
|
|
||||||
# If asked to
|
# If asked to
|
||||||
IF(SERIAL_BUILD_EXAMPLES)
|
IF(SERIAL_BUILD_EXAMPLES)
|
||||||
# Compile the Test program
|
# Compile the Serial Test program
|
||||||
add_executable(serial_example examples/serial_example.cpp)
|
add_executable(serial_example examples/serial_example.cc)
|
||||||
# Link the Test program to the Serial library
|
# Link the Test program to the Serial library
|
||||||
target_link_libraries(serial_example serial)
|
target_link_libraries(serial_example serial)
|
||||||
|
|
||||||
|
# Compile the Serial Listener Test program
|
||||||
|
add_executable(serial_listener_example
|
||||||
|
examples/serial_listener_example.cc)
|
||||||
|
# Link the Test program to the Serial library
|
||||||
|
target_link_libraries(serial_listener_example serial)
|
||||||
ENDIF(SERIAL_BUILD_EXAMPLES)
|
ENDIF(SERIAL_BUILD_EXAMPLES)
|
||||||
|
|
||||||
## Build tests
|
## Build tests
|
||||||
|
|
||||||
# If asked to
|
# If asked to
|
||||||
IF(SERIAL_BUILD_TESTS)
|
IF(SERIAL_BUILD_TESTS)
|
||||||
# none yet...
|
# Find Google Test
|
||||||
|
enable_testing()
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
include_directories(${GTEST_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# Compile the Serial Listener Test program
|
||||||
|
add_executable(serial_listener_tests tests/serial_listener_tests.cc)
|
||||||
|
# Link the Test program to the serial library
|
||||||
|
target_link_libraries(serial_listener_tests ${GTEST_BOTH_LIBRARIES}
|
||||||
|
serial)
|
||||||
|
add_test(AllTestsIntest_serial serial_listener_tests)
|
||||||
ENDIF(SERIAL_BUILD_TESTS)
|
ENDIF(SERIAL_BUILD_TESTS)
|
||||||
|
|
||||||
## Setup install and uninstall
|
## Setup install and uninstall
|
||||||
@ -95,7 +116,9 @@ IF(NOT SERIAL_DONT_CONFIGURE_INSTALL)
|
|||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
)
|
)
|
||||||
|
|
||||||
INSTALL(FILES include/serial/serial.h DESTINATION include/serial)
|
INSTALL(FILES include/serial/serial.h
|
||||||
|
include/serial/serial_listener.h
|
||||||
|
DESTINATION include/serial)
|
||||||
|
|
||||||
IF(NOT CMAKE_FIND_INSTALL_PATH)
|
IF(NOT CMAKE_FIND_INSTALL_PATH)
|
||||||
set(CMAKE_FIND_INSTALL_PATH ${CMAKE_ROOT})
|
set(CMAKE_FIND_INSTALL_PATH ${CMAKE_ROOT})
|
||||||
|
|||||||
@ -30,4 +30,4 @@ ifneq ($(MAKE),)
|
|||||||
else
|
else
|
||||||
cd build && make
|
cd build && make
|
||||||
endif
|
endif
|
||||||
# cd bin && ./serial_tests
|
cd bin && ./serial_listener_tests
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include "mdc2250/serial_listener.h"
|
#include "serial/serial_listener.h"
|
||||||
|
|
||||||
/***** Inline Functions *****/
|
/***** Inline Functions *****/
|
||||||
|
|
||||||
@ -22,6 +22,18 @@ inline void defaultExceptionCallback(const std::exception &error) {
|
|||||||
|
|
||||||
using namespace serial;
|
using namespace serial;
|
||||||
|
|
||||||
|
void
|
||||||
|
_delimeter_tokenizer (std::string &data, std::vector<std::string> &tokens,
|
||||||
|
std::string delimeter)
|
||||||
|
{
|
||||||
|
boost::split(tokens, data, boost::is_any_of(delimeter));
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenizerType
|
||||||
|
delimeter_tokenizer (std::string delimeter) {
|
||||||
|
return boost::bind(_delimeter_tokenizer, _1, _2, delimeter);
|
||||||
|
}
|
||||||
|
|
||||||
/***** Listener Class Functions *****/
|
/***** Listener Class Functions *****/
|
||||||
|
|
||||||
SerialListener::SerialListener() : listening(false) {
|
SerialListener::SerialListener() : listening(false) {
|
||||||
@ -32,20 +44,25 @@ SerialListener::SerialListener() : listening(false) {
|
|||||||
this->warn = defaultWarningCallback;
|
this->warn = defaultWarningCallback;
|
||||||
this->default_handler = NULL;
|
this->default_handler = NULL;
|
||||||
|
|
||||||
|
// Set default tokenizer
|
||||||
|
this->setTokenizer(delimeter_tokenizer("\r"));
|
||||||
|
|
||||||
// Set default ttl
|
// Set default ttl
|
||||||
using namespace boost::posix_time;
|
this->setTimeToLive();
|
||||||
this->ttl = time_duration(milliseconds(1000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialListener::~SerialListener() {
|
SerialListener::~SerialListener() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialListener::setTimeToLive(size_t ms) {
|
void
|
||||||
this->ttl = time_duration(boost::posix_time::milliseconds(ms));
|
SerialListener::setTimeToLive(size_t ms) {
|
||||||
|
using namespace boost::posix_time;
|
||||||
|
this->ttl = time_duration(milliseconds(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialListener::startListening(Serial * serial_port) {
|
void
|
||||||
|
SerialListener::startListening(Serial * serial_port) {
|
||||||
if (this->listening) {
|
if (this->listening) {
|
||||||
throw(SerialListenerException("Already listening."));
|
throw(SerialListenerException("Already listening."));
|
||||||
return;
|
return;
|
||||||
@ -61,13 +78,31 @@ void SerialListener::startListening(Serial * serial_port) {
|
|||||||
listen_thread = boost::thread(boost::bind(&SerialListener::listen, this));
|
listen_thread = boost::thread(boost::bind(&SerialListener::listen, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialListener::stopListening() {
|
void
|
||||||
|
SerialListener::stopListening() {
|
||||||
|
// Stop listening and clear buffers
|
||||||
listening = false;
|
listening = false;
|
||||||
listen_thread.join();
|
listen_thread.join();
|
||||||
|
this->buffer = "";
|
||||||
|
this->lines.clear();
|
||||||
|
this->ttls.clear();
|
||||||
this->serial_port = NULL;
|
this->serial_port = NULL;
|
||||||
|
|
||||||
|
// Delete all the filters
|
||||||
|
this->stopListeningForAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialListener::listen() {
|
void
|
||||||
|
SerialListener::stopListeningForAll() {
|
||||||
|
boost::mutex::scoped_lock l(filter_mux);
|
||||||
|
filters.clear();
|
||||||
|
comparators.clear();
|
||||||
|
callbacks.clear();
|
||||||
|
condition_vars.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SerialListener::listen() {
|
||||||
// Make sure there is a serial port
|
// Make sure there is a serial port
|
||||||
if (this->serial_port == NULL) {
|
if (this->serial_port == NULL) {
|
||||||
this->handle_exc(SerialListenerException("Invalid serial port."));
|
this->handle_exc(SerialListenerException("Invalid serial port."));
|
||||||
@ -82,17 +117,20 @@ void SerialListener::listen() {
|
|||||||
size_t amount_to_read = determineAmountToRead();
|
size_t amount_to_read = determineAmountToRead();
|
||||||
// Read some
|
// Read some
|
||||||
std::string temp = this->serial_port->read(amount_to_read);
|
std::string temp = this->serial_port->read(amount_to_read);
|
||||||
if (temp.length() == 0) {
|
// If nothing was read and there is nothing in the lines, then we
|
||||||
// If nothing was read don't interate through the filters
|
// don't need to interate through the filters
|
||||||
|
if (temp.length() == 0 && lines.size() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Add the new data to the buffer
|
||||||
this->buffer += temp;
|
this->buffer += temp;
|
||||||
if (this->buffer.find("\r") == std::string::npos) {
|
|
||||||
// If there is no return carrage in the buffer, then a command hasn't
|
// If there is no return carrage in the buffer, then a command hasn't
|
||||||
// been completed.
|
// been completed and if there is no data in the lines buffer, then
|
||||||
|
// continue.
|
||||||
|
if (this->buffer.find("\r") == std::string::npos && lines.size() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Listen once
|
// Listen once, this parses the buffer and filters the data in lines
|
||||||
buffer = this->listenOnce(buffer);
|
buffer = this->listenOnce(buffer);
|
||||||
// Done parsing lines and buffer should now be set to the left overs
|
// Done parsing lines and buffer should now be set to the left overs
|
||||||
} // while (this->listening)
|
} // while (this->listening)
|
||||||
@ -101,35 +139,40 @@ void SerialListener::listen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SerialListener::listenOnce(std::string data) {
|
// TODO: as it is, each line is passed to filters repeatedly until they are
|
||||||
|
// too old... Change it to only send each line to each filter once and
|
||||||
|
// then send to new fitlers up until it is too old.
|
||||||
|
std::string
|
||||||
|
SerialListener::listenOnce(std::string data) {
|
||||||
std::string left_overs;
|
std::string left_overs;
|
||||||
// TODO: Make the delimeter settable
|
std::vector<uuid_type> to_be_erased;
|
||||||
// Split the buffer by the delimeter
|
// Tokenize the new data
|
||||||
std::vector<std::string> new_lines;
|
std::vector<std::string> new_lines;
|
||||||
boost::split(new_lines, data, boost::is_any_of("\r")); // it only uses \r
|
tokenize(data, new_lines);
|
||||||
// Iterate through new lines and add times to them
|
// Iterate through new lines and add times to them
|
||||||
std::vector<std::string>::iterator it_lines;
|
std::vector<std::string>::iterator it_new;
|
||||||
for(it_lines=new_lines.begin(); it_lines!=new_lines.end(); it_lines++) {
|
for(it_new=new_lines.begin(); it_new != new_lines.end(); it_new++) {
|
||||||
// The last line needs to be put back in the buffer always:
|
// The last line needs to be put back in the buffer always:
|
||||||
// In the case that the string ends with \r the last element will be
|
// In the case that the string ends with \r the last element will be
|
||||||
// empty (""). In the case that it does not the last element will be
|
// empty (""). In the case that it does not the last element will be
|
||||||
// what is left over from the next message that hasn't sent
|
// what is left over from the next message that hasn't sent
|
||||||
// everything. Ex.: "?$1E\r" -> ["?$1E", ""] and
|
// everything. Ex.: "?$1E\r" -> ["?$1E", ""] and
|
||||||
// "?$1E\r$1E=Robo" -> ["?$1E","$1E=Robo"]
|
// "?$1E\r$1E=Robo" -> ["?$1E","$1E=Robo"]
|
||||||
if (it_lines == new_lines.end()-1) {
|
if (it_new == new_lines.end()-1) {
|
||||||
left_overs = (*it_lines);
|
left_overs = (*it_new);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uuid_t uuid = random_generator();
|
uuid_type uuid = random_generator();
|
||||||
lines.insert(std::pair<const uuid_t,std::string>(uuid,(*it_lines)));
|
lines.insert(std::pair<const uuid_type,std::string>(uuid,(*it_new)));
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
ttls.insert(std::pair<const uuid_t,ptime>
|
ttls.insert(std::pair<const uuid_type,ptime>
|
||||||
(uuid,ptime(microsec_clock::local_time())));
|
(uuid,ptime(microsec_clock::local_time())));
|
||||||
}
|
}
|
||||||
// Iterate through the lines checking for a match
|
// Iterate through the lines checking for a match
|
||||||
|
std::map<const uuid_type,std::string>::iterator it_lines;
|
||||||
for(it_lines=lines.begin(); it_lines!=lines.end(); it_lines++) {
|
for(it_lines=lines.begin(); it_lines!=lines.end(); it_lines++) {
|
||||||
std::string line = (*it_lines).second;
|
std::string line = (*it_lines).second;
|
||||||
uuid_t uuid = (*it_lines).first
|
uuid_type uuid = (*it_lines).first;
|
||||||
// If the line is empty, continue
|
// If the line is empty, continue
|
||||||
if (line.length() == 0) {
|
if (line.length() == 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -139,74 +182,80 @@ std::string SerialListener::listenOnce(std::string data) {
|
|||||||
// Get the filter lock
|
// Get the filter lock
|
||||||
boost::mutex::scoped_lock l(filter_mux);
|
boost::mutex::scoped_lock l(filter_mux);
|
||||||
// Iterate through each filter
|
// Iterate through each filter
|
||||||
std::map<const uuid_t,std::string>::iterator it;
|
std::map<const uuid_type,std::string>::iterator it;
|
||||||
for(it=filters.begin(); it!=filters.end(); it++) {
|
for(it=filters.begin(); it!=filters.end(); it++) {
|
||||||
if (comparators[(*it).first](line)) { // If comparator matches line
|
if (comparators[(*it).first](line)) { // If comparator matches line
|
||||||
if ((*it).second == "non-blocking") {
|
if ((*it).second == "non-blocking") {
|
||||||
// TODO: Put this callback execution into a queue
|
// TODO: Put this callback execution into a queue. And if I do, make sure to
|
||||||
|
// keep the line instance around until the callback is done...
|
||||||
// If non-blocking run the callback
|
// If non-blocking run the callback
|
||||||
callbacks[(*it).first](line);
|
callbacks[(*it).first](line);
|
||||||
lines.erase(uuid);
|
to_be_erased.push_back(uuid);
|
||||||
ttls.erase(uuid);
|
|
||||||
erased = true;
|
erased = true;
|
||||||
} else if ((*it).second == "blocking") {
|
} else if ((*it).second == "blocking") {
|
||||||
// If blocking then notify the waiting call to continue
|
// If blocking then notify the waiting call to continue
|
||||||
condition_vars[(*it).first]->notify_all();
|
condition_vars[(*it).first]->notify_all();
|
||||||
lines.erase(uuid);
|
to_be_erased.push_back(uuid);
|
||||||
ttls.erase(uuid);
|
|
||||||
erased = true;
|
erased = true;
|
||||||
}
|
}
|
||||||
matched = true;
|
matched = true;
|
||||||
break; // It matched, continue to next line
|
break; // It matched, continue to next line
|
||||||
}
|
}
|
||||||
} // for(it=filters.begin(); it!=filters.end(); it++)
|
} // for(it=filters.begin(); it!=filters.end(); it++)
|
||||||
// If the comparator doesn't match try another
|
|
||||||
if (!matched) { // Try to send to default handler
|
|
||||||
if (this->default_handler) {
|
|
||||||
this->default_handler(line);
|
|
||||||
lines.erase(uuid);
|
|
||||||
ttls.erase(uuid);
|
|
||||||
erased = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If not already erased check how old it is, remove the too old
|
// If not already erased check how old it is, remove the too old
|
||||||
if (!erased) {
|
if (!erased) {
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
if (ptime(microsec_clock::local_time())-ttls[uuid] > ttl) {
|
if (ptime(microsec_clock::local_time())-ttls[uuid] > ttl) {
|
||||||
lines.erase(uuid);
|
// If there is a default handler pass it on
|
||||||
ttls.erase(uuid);
|
if (this->default_handler) {
|
||||||
|
// TODO: see above about callback execution queue
|
||||||
|
this->default_handler(line);
|
||||||
|
}
|
||||||
|
to_be_erased.push_back(uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // for(it_lines=lines.begin(); it_lines!=lines.end(); it_lines++)
|
} // for(it_lines=lines.begin(); it_lines!=lines.end(); it_lines++)
|
||||||
|
// Remove any lines that need to be erased
|
||||||
|
// (this must be done outside the iterator to prevent problems incrementing
|
||||||
|
// the iterator)
|
||||||
|
std::vector<uuid_type>::iterator it;
|
||||||
|
for (it=to_be_erased.begin(); it != to_be_erased.end(); it++) {
|
||||||
|
lines.erase((*it));
|
||||||
|
ttls.erase((*it));
|
||||||
|
}
|
||||||
|
// Return the left_overs
|
||||||
return left_overs;
|
return left_overs;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SerialListener::determineAmountToRead() {
|
size_t
|
||||||
|
SerialListener::determineAmountToRead() {
|
||||||
// TODO: Make a more intelligent method based on the length of the things
|
// TODO: Make a more intelligent method based on the length of the things
|
||||||
// filters are looking for. i.e.: if the filter is looking for 'V=XX\r'
|
// filters are looking for. i.e.: if the filter is looking for 'V=XX\r'
|
||||||
// make the read amount at least 5.
|
// make the read amount at least 5.
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialListener::listenForOnceComparator(std::string line) {
|
bool
|
||||||
|
SerialListener::listenForOnceComparator(std::string line) {
|
||||||
if (line == current_listen_for_one_target)
|
if (line == current_listen_for_one_target)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialListener::listenForOnce(std::string token, size_t milliseconds) {
|
bool
|
||||||
|
SerialListener::listenForStringOnce(std::string token, size_t milliseconds) {
|
||||||
boost::condition_variable cond;
|
boost::condition_variable cond;
|
||||||
boost::mutex mut;
|
boost::mutex mut;
|
||||||
current_listen_for_one_target = token;
|
current_listen_for_one_target = token;
|
||||||
|
|
||||||
// Create blocking filter
|
// Create blocking filter
|
||||||
uuid_t uuid = random_generator();
|
uuid_type uuid = random_generator();
|
||||||
std::pair<const uuid_t,std::string>
|
std::pair<const uuid_type,std::string>
|
||||||
filter_pair(uuid, "blocking");
|
filter_pair(uuid, "blocking");
|
||||||
std::pair<const uuid_t,ComparatorType>
|
std::pair<const uuid_type,ComparatorType>
|
||||||
comparator_pair(uuid,
|
comparator_pair(uuid,
|
||||||
boost::bind(&SerialListener::listenForOnceComparator, this, _1));
|
boost::bind(&SerialListener::listenForOnceComparator, this, _1));
|
||||||
std::pair<const uuid_t,boost::condition_variable*>
|
std::pair<const uuid_type,boost::condition_variable*>
|
||||||
condition_pair(uuid, &cond);
|
condition_pair(uuid, &cond);
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(filter_mux);
|
boost::mutex::scoped_lock l(filter_mux);
|
||||||
@ -233,17 +282,16 @@ bool SerialListener::listenForOnce(std::string token, size_t milliseconds) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::uuids::uuid
|
uuid_type
|
||||||
SerialListener::listenFor(ComparatorType comparator,
|
SerialListener::listenFor(ComparatorType comparator, DataCallback callback)
|
||||||
SerialCallback callback)
|
|
||||||
{
|
{
|
||||||
// Create Filter
|
// Create Filter
|
||||||
uuid_t uuid = random_generator();
|
uuid_type uuid = random_generator();
|
||||||
std::pair<const uuid_t,std::string>
|
std::pair<const uuid_type,std::string>
|
||||||
filter_pair(uuid, "non-blocking");
|
filter_pair(uuid, "non-blocking");
|
||||||
std::pair<const uuid_t,ComparatorType>
|
std::pair<const uuid_type,ComparatorType>
|
||||||
comparator_pair(uuid, comparator);
|
comparator_pair(uuid, comparator);
|
||||||
std::pair<const uuid_t,SerialCallback>
|
std::pair<const uuid_type,DataCallback>
|
||||||
callback_pair(uuid, callback);
|
callback_pair(uuid, callback);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -256,7 +304,8 @@ SerialListener::listenFor(ComparatorType comparator,
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialListener::stopListeningFor(boost::uuids::uuid filter_uuid) {
|
void
|
||||||
|
SerialListener::stopListeningFor(uuid_type filter_uuid) {
|
||||||
// Delete filter
|
// Delete filter
|
||||||
boost::mutex::scoped_lock l(filter_mux);
|
boost::mutex::scoped_lock l(filter_mux);
|
||||||
filters.erase(filter_uuid);
|
filters.erase(filter_uuid);
|
||||||
|
|||||||
BIN
tests/proof_of_concepts/tokenizer.cc.out
Executable file
BIN
tests/proof_of_concepts/tokenizer.cc.out
Executable file
Binary file not shown.
@ -2,13 +2,11 @@
|
|||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
#define SERIAL_LISTENER_TEST true
|
|
||||||
|
|
||||||
// OMG this is so nasty...
|
// OMG this is so nasty...
|
||||||
#define private public
|
#define private public
|
||||||
#define protected public
|
#define protected public
|
||||||
|
|
||||||
#include "mdc2250/serial_listener.h"
|
#include "serial/serial_listener.h"
|
||||||
using namespace serial;
|
using namespace serial;
|
||||||
|
|
||||||
static size_t global_count, global_listen_count;
|
static size_t global_count, global_listen_count;
|
||||||
@ -26,8 +24,8 @@ protected:
|
|||||||
listener.default_handler = default_handler;
|
listener.default_handler = default_handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_lookForOnce() {
|
void execute_listenForStringOnce() {
|
||||||
listener.listenForOnce("?$1E", 1000);
|
listener.listenForStringOnce("?$1E", 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialListener listener;
|
SerialListener listener;
|
||||||
@ -37,6 +35,8 @@ protected:
|
|||||||
TEST_F(SerialListenerTests, ignoresEmptyString) {
|
TEST_F(SerialListenerTests, ignoresEmptyString) {
|
||||||
global_count = 0;
|
global_count = 0;
|
||||||
|
|
||||||
|
listener.listenOnce("");
|
||||||
|
boost::this_thread::sleep(boost::posix_time::milliseconds(11));
|
||||||
listener.listenOnce("");
|
listener.listenOnce("");
|
||||||
|
|
||||||
ASSERT_TRUE(global_count == 0);
|
ASSERT_TRUE(global_count == 0);
|
||||||
@ -46,6 +46,8 @@ TEST_F(SerialListenerTests, ignoresPartialMessage) {
|
|||||||
global_count = 0;
|
global_count = 0;
|
||||||
|
|
||||||
listener.listenOnce("?$1E\r$1E=Robo");
|
listener.listenOnce("?$1E\r$1E=Robo");
|
||||||
|
boost::this_thread::sleep(boost::posix_time::milliseconds(11));
|
||||||
|
listener.listenOnce("");
|
||||||
|
|
||||||
ASSERT_EQ(global_count, 1);
|
ASSERT_EQ(global_count, 1);
|
||||||
}
|
}
|
||||||
@ -54,11 +56,13 @@ TEST_F(SerialListenerTests, listenForOnceWorks) {
|
|||||||
global_count = 0;
|
global_count = 0;
|
||||||
|
|
||||||
boost::thread t(
|
boost::thread t(
|
||||||
boost::bind(&SerialListenerTests::execute_lookForOnce, this));
|
boost::bind(&SerialListenerTests::execute_listenForStringOnce, this));
|
||||||
|
|
||||||
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
|
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
|
||||||
|
|
||||||
listener.listenOnce("\r+\r?$1E\r$1E=Robo");
|
listener.listenOnce("\r+\r?$1E\r$1E=Robo");
|
||||||
|
boost::this_thread::sleep(boost::posix_time::milliseconds(11));
|
||||||
|
listener.listenOnce("");
|
||||||
|
|
||||||
ASSERT_TRUE(t.timed_join(boost::posix_time::milliseconds(1500)));
|
ASSERT_TRUE(t.timed_join(boost::posix_time::milliseconds(1500)));
|
||||||
|
|
||||||
@ -74,11 +78,13 @@ TEST_F(SerialListenerTests, listenForOnceTimesout) {
|
|||||||
global_count = 0;
|
global_count = 0;
|
||||||
|
|
||||||
boost::thread t(
|
boost::thread t(
|
||||||
boost::bind(&SerialListenerTests::execute_lookForOnce, this));
|
boost::bind(&SerialListenerTests::execute_listenForStringOnce, this));
|
||||||
|
|
||||||
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
|
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
|
||||||
|
|
||||||
listener.listenOnce("\r+\r?$1ENOTRIGHT\r$1E=Robo");
|
listener.listenOnce("\r+\r?$1ENOTRIGHT\r$1E=Robo");
|
||||||
|
boost::this_thread::sleep(boost::posix_time::milliseconds(11));
|
||||||
|
listener.listenOnce("");
|
||||||
|
|
||||||
ASSERT_TRUE(t.timed_join(boost::posix_time::milliseconds(1500)));
|
ASSERT_TRUE(t.timed_join(boost::posix_time::milliseconds(1500)));
|
||||||
|
|
||||||
@ -104,6 +110,8 @@ TEST_F(SerialListenerTests, listenForWorks) {
|
|||||||
listener.listenFor(listenForComparator, listenForCallback);
|
listener.listenFor(listenForComparator, listenForCallback);
|
||||||
|
|
||||||
listener.listenOnce("\r+\rV=05:06\r?$1E\rV=06:05\r$1E=Robo");
|
listener.listenOnce("\r+\rV=05:06\r?$1E\rV=06:05\r$1E=Robo");
|
||||||
|
boost::this_thread::sleep(boost::posix_time::milliseconds(11));
|
||||||
|
listener.listenOnce("");
|
||||||
|
|
||||||
ASSERT_EQ(global_count, 2);
|
ASSERT_EQ(global_count, 2);
|
||||||
ASSERT_EQ(global_listen_count, 2);
|
ASSERT_EQ(global_listen_count, 2);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user