mirror of
https://github.com/wjwwood/serial.git
synced 2026-01-22 11:44:53 +08:00
Got some serial listener tests working
This commit is contained in:
parent
6983d1145f
commit
20f552bc80
@ -18,7 +18,7 @@ int run(int argc, char **argv)
|
||||
sscanf(argv[2], "%lu", &baud);
|
||||
|
||||
// port, baudrate, timeout in milliseconds
|
||||
serial::Serial serial(port, baud, 250);
|
||||
serial::Serial serial(port, baud, 1000);
|
||||
|
||||
std::cout << "Is the serial port open?";
|
||||
if(serial.isOpen())
|
||||
|
||||
@ -102,8 +102,10 @@ class IOException : public std::exception
|
||||
const char* e_what_;
|
||||
int errno_;
|
||||
public:
|
||||
explicit IOException (int errnum) : e_what_ (strerror (errnum)), errno_(errnum) {}
|
||||
explicit IOException (const char * description) : e_what_ (description), errno_(0) {}
|
||||
explicit IOException (int errnum)
|
||||
: e_what_ (strerror (errnum)), errno_(errnum) {}
|
||||
explicit IOException (const char * description)
|
||||
: e_what_ (description), errno_(0) {}
|
||||
|
||||
int getErrorNumber () { return errno_; }
|
||||
|
||||
@ -113,7 +115,7 @@ public:
|
||||
if (errno_ == 0)
|
||||
ss << "IO Exception " << e_what_ << " failed.";
|
||||
else
|
||||
ss << "IO Exception " << errno_ << ":" << e_what_ << " failed.";
|
||||
ss << "IO Exception (" << errno_ << "): " << e_what_ << " failed.";
|
||||
return ss.str ().c_str ();
|
||||
}
|
||||
};
|
||||
|
||||
@ -663,10 +663,8 @@ private:
|
||||
|
||||
// Gets some data from the serial port
|
||||
void readSomeData (std::string&, size_t);
|
||||
// Runs the new tokens through the filters
|
||||
void filterNewTokens (std::vector<TokenPtr> new_tokens);
|
||||
// Given a filter_id and a list of tokens, return list of matched tokens
|
||||
void filter (FilterPtr filter, std::vector<TokenPtr> &tokens);
|
||||
// Runs the new_tokens through all the filters
|
||||
void filter (std::vector<TokenPtr> &tokens);
|
||||
// Function that loops while listening is true
|
||||
void listen ();
|
||||
// Target of callback thread
|
||||
|
||||
179
src/impl/unix.cc
179
src/impl/unix.cc
@ -31,7 +31,6 @@ using serial::SerialExecption;
|
||||
using serial::PortNotOpenedException;
|
||||
using serial::IOException;
|
||||
|
||||
|
||||
Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
|
||||
long timeout, bytesize_t bytesize,
|
||||
parity_t parity, stopbits_t stopbits,
|
||||
@ -115,131 +114,8 @@ Serial::SerialImpl::reconfigurePort ()
|
||||
#endif
|
||||
|
||||
// setup baud rate
|
||||
bool custom_baud = false;
|
||||
speed_t baud;
|
||||
switch (baudrate_)
|
||||
{
|
||||
#ifdef B0
|
||||
case 0: baud = B0; break;
|
||||
#endif
|
||||
#ifdef B50
|
||||
case 50: baud = B50; break;
|
||||
#endif
|
||||
#ifdef B75
|
||||
case 75: baud = B75; break;
|
||||
#endif
|
||||
#ifdef B110
|
||||
case 110: baud = B110; break;
|
||||
#endif
|
||||
#ifdef B134
|
||||
case 134: baud = B134; break;
|
||||
#endif
|
||||
#ifdef B150
|
||||
case 150: baud = B150; break;
|
||||
#endif
|
||||
#ifdef B200
|
||||
case 200: baud = B200; break;
|
||||
#endif
|
||||
#ifdef B300
|
||||
case 300: baud = B300; break;
|
||||
#endif
|
||||
#ifdef B600
|
||||
case 600: baud = B600; break;
|
||||
#endif
|
||||
#ifdef B1200
|
||||
case 1200: baud = B1200; break;
|
||||
#endif
|
||||
#ifdef B1800
|
||||
case 1800: baud = B1800; break;
|
||||
#endif
|
||||
#ifdef B2400
|
||||
case 2400: baud = B2400; break;
|
||||
#endif
|
||||
#ifdef B4800
|
||||
case 4800: baud = B4800; break;
|
||||
#endif
|
||||
#ifdef B7200
|
||||
case 7200: baud = B7200; break;
|
||||
#endif
|
||||
#ifdef B9600
|
||||
case 9600: baud = B9600; break;
|
||||
#endif
|
||||
#ifdef B14400
|
||||
case 14400: baud = B14400; break;
|
||||
#endif
|
||||
#ifdef B19200
|
||||
case 19200: baud = B19200; break;
|
||||
#endif
|
||||
#ifdef B28800
|
||||
case 28800: baud = B28800; break;
|
||||
#endif
|
||||
#ifdef B57600
|
||||
case 57600: baud = B57600; break;
|
||||
#endif
|
||||
#ifdef B76800
|
||||
case 76800: baud = B76800; break;
|
||||
#endif
|
||||
#ifdef B38400
|
||||
case 38400: baud = B38400; break;
|
||||
#endif
|
||||
#ifdef B115200
|
||||
case 115200: baud = B115200; break;
|
||||
#endif
|
||||
#ifdef B128000
|
||||
case 128000: baud = B128000; break;
|
||||
#endif
|
||||
#ifdef B153600
|
||||
case 153600: baud = B153600; break;
|
||||
#endif
|
||||
#ifdef B230400
|
||||
case 230400: baud = B230400; break;
|
||||
#endif
|
||||
#ifdef B256000
|
||||
case 256000: baud = B256000; break;
|
||||
#endif
|
||||
#ifdef B460800
|
||||
case 460800: baud = B460800; break;
|
||||
#endif
|
||||
#ifdef B921600
|
||||
case 921600: baud = B921600; break;
|
||||
#endif
|
||||
default:
|
||||
custom_baud = true;
|
||||
// Mac OS X 10.x Support
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define IOSSIOSPEED _IOW('T', 2, speed_t)
|
||||
int new_baud = static_cast<int> (baudrate_);
|
||||
if (ioctl (fd_, IOSSIOSPEED, &new_baud, 1) < 0)
|
||||
{
|
||||
throw IOException (errno);
|
||||
}
|
||||
// Linux Support
|
||||
#elif defined(__linux__)
|
||||
struct serial_struct ser;
|
||||
ioctl(fd_, TIOCGSERIAL, &ser);
|
||||
// set custom divisor
|
||||
ser.custom_divisor = ser.baud_base / baudrate;
|
||||
// update flags
|
||||
ser.flags &= ~ASYNC_SPD_MASK;
|
||||
ser.flags |= ASYNC_SPD_CUST;
|
||||
|
||||
if (ioctl(fd_, TIOCSSERIAL, buf) < 0)
|
||||
{
|
||||
throw IOException (errno);
|
||||
}
|
||||
#else
|
||||
throw invalid_argument ("OS does not currently support custom bauds");
|
||||
#endif
|
||||
}
|
||||
if (custom_baud == false)
|
||||
{
|
||||
#ifdef _BSD_SOURCE
|
||||
::cfsetspeed(&options, baud);
|
||||
#else
|
||||
::cfsetispeed(&options, baud);
|
||||
::cfsetospeed(&options, baud);
|
||||
#endif
|
||||
}
|
||||
// TODO(ash_git): validate baud rate
|
||||
cfsetspeed(&options, baudrate_);
|
||||
|
||||
// setup char len
|
||||
options.c_cflag &= (unsigned long) ~CSIZE;
|
||||
@ -389,6 +265,7 @@ Serial::SerialImpl::read (char* buf, size_t size)
|
||||
bytes_read = ::read (fd_, buf, size);
|
||||
// read should always return some data as select reported it was
|
||||
// ready to read when we get to this point.
|
||||
// printf("bytes_read: %lu\n", bytes_read);
|
||||
if (bytes_read < 1)
|
||||
{
|
||||
// Disconnected devices, at least on Linux, show the
|
||||
@ -414,51 +291,25 @@ Serial::SerialImpl::write (const string &data)
|
||||
{
|
||||
throw PortNotOpenedException ("Serial::write");
|
||||
}
|
||||
|
||||
fd_set writefds;
|
||||
ssize_t bytes_written = 0;
|
||||
while (true)
|
||||
|
||||
ssize_t n = ::write (fd_, data.c_str (), data.length ());
|
||||
|
||||
if (n != static_cast<ssize_t> (data.length ()))
|
||||
{
|
||||
if (timeout_ != -1)
|
||||
throw IOException ("Write did not complete");
|
||||
}
|
||||
else if (n == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
FD_ZERO (&writefds);
|
||||
FD_SET (fd_, &writefds);
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = timeout_ / 1000;
|
||||
timeout.tv_usec = static_cast<int> (timeout_ % 1000) * 1000;
|
||||
int r = select (fd_ + 1, NULL, &writefds, NULL, &timeout);
|
||||
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (r == -1)
|
||||
{
|
||||
throw IOException (errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout_ == -1 || FD_ISSET (fd_, &writefds))
|
||||
{
|
||||
bytes_written = ::write (fd_, data.c_str (), data.length ());
|
||||
// read should always return some data as select reported it was
|
||||
// ready to read when we get to this point.
|
||||
if (bytes_written < 1)
|
||||
{
|
||||
// Disconnected devices, at least on Linux, show the
|
||||
// behavior that they are always ready to read immediately
|
||||
// but reading returns nothing.
|
||||
throw SerialExecption ("device reports readiness to read but "
|
||||
"returned no data (device disconnected?)");
|
||||
}
|
||||
break;
|
||||
return write (data);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
throw IOException (errno);
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<size_t> (bytes_written);
|
||||
return static_cast<size_t> (n);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -50,8 +50,6 @@ SerialListener::callback() {
|
||||
std::pair<FilterPtr,TokenPtr> pair;
|
||||
while (this->listening) {
|
||||
if (this->callback_queue.timed_wait_and_pop(pair, 10)) {
|
||||
std::cerr << "Got something off the callback queue: ";
|
||||
std::cerr << (*pair.second) << std::endl;
|
||||
if (this->listening) {
|
||||
try {
|
||||
pair.first->callback_((*pair.second));
|
||||
@ -118,37 +116,32 @@ SerialListener::readSomeData(std::string &temp, size_t this_many) {
|
||||
this->handle_exc(SerialListenerException("Serial port not open."));
|
||||
}
|
||||
temp = this->serial_port_->read(this_many);
|
||||
// if (temp.length() > 0) {
|
||||
std::cerr << "SerialListener read (" << temp.length() << "): ";
|
||||
std::cerr << temp << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
void
|
||||
SerialListener::filterNewTokens (std::vector<TokenPtr> new_tokens) {
|
||||
// Iterate through the filters, checking each against new tokens
|
||||
SerialListener::filter(std::vector<TokenPtr> &tokens) {
|
||||
// Lock the filters while filtering
|
||||
boost::mutex::scoped_lock lock(filter_mux);
|
||||
std::vector<FilterPtr>::iterator it;
|
||||
for (it=filters.begin(); it!=filters.end(); it++) {
|
||||
this->filter((*it), new_tokens);
|
||||
} // for (it=filters.begin(); it!=filters.end(); it++)
|
||||
// Put the last token back in the data buffer
|
||||
this->data_buffer = (*new_tokens.back());
|
||||
}
|
||||
|
||||
void
|
||||
SerialListener::filter (FilterPtr filter, std::vector<TokenPtr> &tokens)
|
||||
{
|
||||
// Iterate through the token uuids and run each against the filter
|
||||
// Iterate through each new token and filter them
|
||||
std::vector<TokenPtr>::iterator it;
|
||||
for (it=tokens.begin(); it!=tokens.end(); it++) {
|
||||
// The last element goes back into the data_buffer, don't filter it
|
||||
if (it == tokens.end()-1)
|
||||
continue;
|
||||
TokenPtr token = (*it);
|
||||
if (filter->comparator_((*token)))
|
||||
callback_queue.push(std::make_pair(filter,token));
|
||||
}
|
||||
bool matched = false;
|
||||
// Iterate through each filter
|
||||
std::vector<FilterPtr>::iterator itt;
|
||||
for (itt=filters.begin(); itt!=filters.end(); itt++) {
|
||||
FilterPtr filter = (*itt);
|
||||
if (filter->comparator_((*token))) {
|
||||
callback_queue.push(std::make_pair(filter,token));
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
} // for (itt=filters.begin(); itt!=filters.end(); itt++)
|
||||
// If matched is false then send it to the default handler
|
||||
if (!matched) {
|
||||
callback_queue.push(std::make_pair(default_filter,token));
|
||||
}
|
||||
} // for (it=tokens.begin(); it!=tokens.end(); it++)
|
||||
}
|
||||
|
||||
void
|
||||
@ -166,8 +159,11 @@ SerialListener::listen() {
|
||||
// Call the tokenizer on the updated buffer
|
||||
std::vector<TokenPtr> new_tokens;
|
||||
this->tokenize(this->data_buffer, new_tokens);
|
||||
// Put the last token back in the data buffer
|
||||
this->data_buffer = (*new_tokens.back());
|
||||
new_tokens.pop_back();
|
||||
// Run the new tokens through existing filters
|
||||
this->filterNewTokens(new_tokens);
|
||||
this->filter(new_tokens);
|
||||
}
|
||||
// Done parsing lines and buffer should now be set to the left overs
|
||||
} // while (this->listening)
|
||||
|
||||
@ -17,7 +17,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define SERIAL_PORT_NAME "/dev/tty.usbserial"
|
||||
// #define SERIAL_PORT_NAME "/dev/tty.usbserial-A900cfJA"
|
||||
#define SERIAL_PORT_NAME "p0"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
@ -32,6 +33,12 @@ using namespace serial;
|
||||
|
||||
static size_t global_count, global_listen_count;
|
||||
|
||||
void filter_handler(std::string token) {
|
||||
global_listen_count++;
|
||||
std::cout << "filter_handler got: " << token << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void default_handler(std::string line) {
|
||||
global_count++;
|
||||
std::cout << "default_handler got: " << line << std::endl;
|
||||
@ -39,7 +46,6 @@ void default_handler(std::string line) {
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
void my_sleep(long milliseconds) {
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(milliseconds));
|
||||
}
|
||||
@ -47,10 +53,8 @@ void my_sleep(long milliseconds) {
|
||||
class SerialListenerTests : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
port1 = new Serial(SERIAL_PORT_NAME, 115200, 250);
|
||||
|
||||
// Need to wait a bit for the Arduino to come up
|
||||
// my_sleep(1000);
|
||||
port1 = new Serial("/dev/pty"SERIAL_PORT_NAME, 115200, 10);
|
||||
port2 = new Serial("/dev/tty"SERIAL_PORT_NAME, 115200, 250);
|
||||
|
||||
listener.setDefaultHandler(default_handler);
|
||||
listener.startListening((*port1));
|
||||
@ -58,12 +62,13 @@ protected:
|
||||
|
||||
virtual void TearDown() {
|
||||
listener.stopListening();
|
||||
port1->close();
|
||||
delete port1;
|
||||
delete port2;
|
||||
}
|
||||
|
||||
SerialListener listener;
|
||||
Serial * port1;
|
||||
Serial * port2;
|
||||
|
||||
};
|
||||
|
||||
@ -71,88 +76,39 @@ TEST_F(SerialListenerTests, handlesPartialMessage) {
|
||||
global_count = 0;
|
||||
std::string input_str = "?$1E\r$1E=Robo";
|
||||
|
||||
ASSERT_EQ(input_str.length(), port1->write(input_str));
|
||||
|
||||
// give some time for the callback thread to finish
|
||||
my_sleep(2000);
|
||||
std::cout << "writing: ?$1E<cr>$1E=Robo" << std::endl;
|
||||
port2->write(input_str);
|
||||
// Allow time for processing
|
||||
my_sleep(50);
|
||||
|
||||
ASSERT_EQ(1, global_count);
|
||||
|
||||
input_str = "?$1E\r$1E=Roboteq\r";
|
||||
std::cout << "writing: ?$1E<cr>$1E=Roboteq<cr>" << std::endl;
|
||||
port2->write(input_str);
|
||||
// Allow time for processing
|
||||
my_sleep(50);
|
||||
|
||||
ASSERT_EQ(3, global_count);
|
||||
}
|
||||
|
||||
// TEST_F(SerialListenerTests, listenForOnceWorks) {
|
||||
// global_count = 0;
|
||||
//
|
||||
// boost::thread t(
|
||||
// boost::bind(&SerialListenerTests::execute_listenForStringOnce, this));
|
||||
//
|
||||
// boost::this_thread::sleep(boost::posix_time::milliseconds(5));
|
||||
//
|
||||
// simulate_loop("\r+\r?$1E\r$1E=Robo");
|
||||
//
|
||||
// ASSERT_TRUE(t.timed_join(boost::posix_time::milliseconds(60)));
|
||||
//
|
||||
// // Make sure the filters are getting deleted
|
||||
// ASSERT_EQ(listener.filters.size(), 0);
|
||||
//
|
||||
// // give some time for the callback thread to finish
|
||||
// stopCallbackThread();
|
||||
//
|
||||
// ASSERT_EQ(global_count, 1);
|
||||
// }
|
||||
//
|
||||
// // lookForOnce should not find it, but timeout after 1000ms, so it should
|
||||
// // still join.
|
||||
// TEST_F(SerialListenerTests, listenForOnceTimesout) {
|
||||
// global_count = 0;
|
||||
//
|
||||
// boost::thread t(
|
||||
// boost::bind(&SerialListenerTests::execute_listenForStringOnce, this));
|
||||
//
|
||||
// boost::this_thread::sleep(boost::posix_time::milliseconds(55));
|
||||
//
|
||||
// simulate_loop("\r+\r?$1ENOTRIGHT\r$1E=Robo");
|
||||
//
|
||||
// ASSERT_TRUE(t.timed_join(boost::posix_time::milliseconds(60)));
|
||||
//
|
||||
// // give some time for the callback thread to finish
|
||||
// stopCallbackThread();
|
||||
//
|
||||
// ASSERT_EQ(global_count, 2);
|
||||
// }
|
||||
//
|
||||
// bool listenForComparator(std::string line) {
|
||||
// // std::cout << "In listenForComparator(" << line << ")" << std::endl;
|
||||
// if (line.substr(0,2) == "V=") {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// void listenForCallback(std::string line) {
|
||||
// // std::cout << "In listenForCallback(" << line << ")" << std::endl;
|
||||
// global_listen_count++;
|
||||
// }
|
||||
//
|
||||
// TEST_F(SerialListenerTests, listenForWorks) {
|
||||
// global_count = 0;
|
||||
// global_listen_count = 0;
|
||||
//
|
||||
// FilterPtr filt_uuid =
|
||||
// listener.listenFor(listenForComparator, listenForCallback);
|
||||
//
|
||||
// simulate_loop("\r+\rV=05:06\r?$1E\rV=06:05\r$1E=Robo");
|
||||
//
|
||||
// // give some time for the callback thread to finish
|
||||
// stopCallbackThread();
|
||||
//
|
||||
// ASSERT_EQ(global_count, 2);
|
||||
// ASSERT_EQ(global_listen_count, 2);
|
||||
//
|
||||
// listener.stopListeningFor(filt_uuid);
|
||||
//
|
||||
// ASSERT_EQ(listener.filters.size(), 0);
|
||||
//
|
||||
// }
|
||||
TEST_F(SerialListenerTests, normalFilterWorks) {
|
||||
global_count = 0;
|
||||
std::string input_str = "?$1E\r$1E=Robo\rV=1334:1337\rT=123";
|
||||
|
||||
// Setup filter
|
||||
FilterPtr filt_1 =
|
||||
listener.createFilter(SerialListener::startsWith("V="), filter_handler);
|
||||
|
||||
std::cout << "writing: ?$1E<cr>$1E=Robo<cr>V=1334:1337<cr>T=123";
|
||||
std::cout << std::endl;
|
||||
port2->write(input_str);
|
||||
// Allow time for processing
|
||||
my_sleep(50);
|
||||
|
||||
ASSERT_EQ(2, global_count);
|
||||
ASSERT_EQ(1, global_listen_count);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user