-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Terraneo Federico
committed
Jul 11, 2011
0 parents
commit a0e8102
Showing
36 changed files
with
4,281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
cmake_minimum_required(VERSION 2.6) | ||
project(TEST) | ||
|
||
## Target | ||
set(TEST_SRCS main.cpp) | ||
add_executable(simple ${TEST_SRCS}) | ||
|
||
## Link libraries | ||
set(BOOST_LIBS thread date_time system) | ||
find_package(Boost COMPONENTS ${BOOST_LIBS} REQUIRED) | ||
target_link_libraries(simple ${Boost_LIBRARIES}) | ||
find_package(Threads REQUIRED) | ||
target_link_libraries(simple ${CMAKE_THREAD_LIBS_INIT}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#Using MinGW distro from http://nuwen.net/mingw.html that contains boost precompiled | ||
|
||
all: | ||
g++ -O2 -c main.cpp -D_WIN32_WINNT=0x0501 | ||
g++ -o simple.exe main.o -s -lwsock32 -lws2_32 -lboost_system | ||
|
||
clean: | ||
del simple.exe main.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* File: SimpleSerial.h | ||
* Author: Terraneo Federico | ||
* Distributed under the Boost Software License, Version 1.0. | ||
* | ||
* Created on September 10, 2009, 12:12 PM | ||
*/ | ||
|
||
#ifndef _SIMPLESERIAL_H | ||
#define _SIMPLESERIAL_H | ||
|
||
#include <boost/asio.hpp> | ||
|
||
class SimpleSerial | ||
{ | ||
public: | ||
/** | ||
* Constructor. | ||
* \param port device name, example "/dev/ttyUSB0" or "COM4" | ||
* \param baud_rate communication speed, example 9600 or 115200 | ||
* \throws boost::system::system_error if cannot open the | ||
* serial device | ||
*/ | ||
SimpleSerial(std::string port, unsigned int baud_rate) | ||
: io(), serial(io,port) | ||
{ | ||
serial.set_option(boost::asio::serial_port_base::baud_rate(baud_rate)); | ||
} | ||
|
||
/** | ||
* Write a string to the serial device. | ||
* \param s string to write | ||
* \throws boost::system::system_error on failure | ||
*/ | ||
void writeString(std::string s) | ||
{ | ||
boost::asio::write(serial,boost::asio::buffer(s.c_str(),s.size())); | ||
} | ||
|
||
/** | ||
* Blocks until a line is received from the serial device. | ||
* Eventual '\n' or '\r\n' characters at the end of the string are removed. | ||
* \return a string containing the received line | ||
* \throws boost::system::system_error on failure | ||
*/ | ||
std::string readLine() | ||
{ | ||
//Reading data char by char, code is optimized for simplicity, not speed | ||
using namespace boost; | ||
char c; | ||
std::string result; | ||
for(;;) | ||
{ | ||
asio::read(serial,asio::buffer(&c,1)); | ||
switch(c) | ||
{ | ||
case '\r': | ||
break; | ||
case '\n': | ||
return result; | ||
default: | ||
result+=c; | ||
} | ||
} | ||
} | ||
|
||
private: | ||
boost::asio::io_service io; | ||
boost::asio::serial_port serial; | ||
}; | ||
|
||
#endif /* _SIMPLESERIAL_H */ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
|
||
#include <iostream> | ||
#include "SimpleSerial.h" | ||
|
||
using namespace std; | ||
using namespace boost; | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
try { | ||
|
||
SimpleSerial serial("/dev/ttyUSB0",115200); | ||
|
||
serial.writeString("Hello world\n"); | ||
|
||
cout<<"Received : "<<serial.readLine()<<" : end"<<endl; | ||
|
||
} catch(boost::system::system_error& e) | ||
{ | ||
cout<<"Error: "<<e.what()<<endl; | ||
return 1; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
cmake_minimum_required(VERSION 2.6) | ||
project(TEST) | ||
|
||
## Target | ||
set(TEST_SRCS main.cpp TimeoutSerial.cpp) | ||
add_executable(timeout ${TEST_SRCS}) | ||
|
||
## Link libraries | ||
set(BOOST_LIBS thread date_time system) | ||
find_package(Boost COMPONENTS ${BOOST_LIBS} REQUIRED) | ||
target_link_libraries(timeout ${Boost_LIBRARIES}) | ||
find_package(Threads REQUIRED) | ||
target_link_libraries(timeout ${CMAKE_THREAD_LIBS_INIT}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#Using MinGW distro from http://nuwen.net/mingw.html that contains boost precompiled | ||
|
||
all: | ||
g++ -O2 -c main.cpp -D_WIN32_WINNT=0x0501 | ||
g++ -O2 -c TimeoutSerial.cpp -D_WIN32_WINNT=0x0501 | ||
g++ -o timeout.exe main.o TimeoutSerial.o -s -lwsock32 -lws2_32 -lboost_system | ||
|
||
clean: | ||
del timeout.exe main.o TimeoutSerial.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
/* | ||
* File: TimeoutSerial.cpp | ||
* Author: Terraneo Federico | ||
* Distributed under the Boost Software License, Version 1.0. | ||
* Created on September 12, 2009, 3:47 PM | ||
* | ||
* v1.04: Fixed bug with timeout set to zero | ||
* | ||
* v1.03: Fix for Mac OS X, now fully working on Mac. | ||
* | ||
* v1.02: Code cleanup, speed improvements, bug fixes. | ||
* | ||
* v1.01: Fixed a bug that caused errors while reading after a timeout. | ||
* | ||
* v1.00: First release. | ||
*/ | ||
|
||
#include "TimeoutSerial.h" | ||
#include <string> | ||
#include <algorithm> | ||
#include <iostream> | ||
#include <boost/bind.hpp> | ||
|
||
using namespace std; | ||
using namespace boost; | ||
|
||
TimeoutSerial::TimeoutSerial(): io(), port(io), timer(io), | ||
timeout(posix_time::seconds(0)) {} | ||
|
||
TimeoutSerial::TimeoutSerial(const std::string& devname, unsigned int baud_rate, | ||
asio::serial_port_base::parity opt_parity, | ||
asio::serial_port_base::character_size opt_csize, | ||
asio::serial_port_base::flow_control opt_flow, | ||
asio::serial_port_base::stop_bits opt_stop) | ||
: io(), port(io), timer(io), timeout(posix_time::seconds(0)) | ||
{ | ||
open(devname,baud_rate,opt_parity,opt_csize,opt_flow,opt_stop); | ||
} | ||
|
||
void TimeoutSerial::open(const std::string& devname, unsigned int baud_rate, | ||
asio::serial_port_base::parity opt_parity, | ||
asio::serial_port_base::character_size opt_csize, | ||
asio::serial_port_base::flow_control opt_flow, | ||
asio::serial_port_base::stop_bits opt_stop) | ||
{ | ||
if(isOpen()) close(); | ||
port.open(devname); | ||
port.set_option(asio::serial_port_base::baud_rate(baud_rate)); | ||
port.set_option(opt_parity); | ||
port.set_option(opt_csize); | ||
port.set_option(opt_flow); | ||
port.set_option(opt_stop); | ||
} | ||
|
||
bool TimeoutSerial::isOpen() const | ||
{ | ||
return port.is_open(); | ||
} | ||
|
||
void TimeoutSerial::close() | ||
{ | ||
if(isOpen()==false) return; | ||
port.close(); | ||
} | ||
|
||
void TimeoutSerial::setTimeout(const posix_time::time_duration& t) | ||
{ | ||
timeout=t; | ||
} | ||
|
||
void TimeoutSerial::write(const char *data, size_t size) | ||
{ | ||
asio::write(port,asio::buffer(data,size)); | ||
} | ||
|
||
void TimeoutSerial::write(const std::vector<char>& data) | ||
{ | ||
asio::write(port,asio::buffer(&data[0],data.size())); | ||
} | ||
|
||
void TimeoutSerial::writeString(const std::string& s) | ||
{ | ||
asio::write(port,asio::buffer(s.c_str(),s.size())); | ||
} | ||
|
||
void TimeoutSerial::read(char *data, size_t size) | ||
{ | ||
if(readData.size()>0)//If there is some data from a previous read | ||
{ | ||
istream is(&readData); | ||
size_t toRead=min(readData.size(),size);//How many bytes to read? | ||
is.read(data,toRead); | ||
data+=toRead; | ||
size-=toRead; | ||
if(size==0) return;//If read data was enough, just return | ||
} | ||
|
||
setupParameters=ReadSetupParameters(data,size); | ||
performReadSetup(setupParameters); | ||
|
||
//For this code to work, there should always be a timeout, so the | ||
//request for no timeout is translated into a very long timeout | ||
if(timeout!=posix_time::seconds(0)) timer.expires_from_now(timeout); | ||
else timer.expires_from_now(posix_time::hours(100000)); | ||
|
||
timer.async_wait(boost::bind(&TimeoutSerial::timeoutExpired,this, | ||
asio::placeholders::error)); | ||
|
||
result=resultInProgress; | ||
bytesTransferred=0; | ||
for(;;) | ||
{ | ||
io.run_one(); | ||
switch(result) | ||
{ | ||
case resultSuccess: | ||
timer.cancel(); | ||
return; | ||
case resultTimeoutExpired: | ||
port.cancel(); | ||
throw(timeout_exception("Timeout expired")); | ||
case resultError: | ||
timer.cancel(); | ||
port.cancel(); | ||
throw(boost::system::system_error(boost::system::error_code(), | ||
"Error while reading")); | ||
//if resultInProgress remain in the loop | ||
} | ||
} | ||
} | ||
|
||
std::vector<char> TimeoutSerial::read(size_t size) | ||
{ | ||
vector<char> result(size,'\0');//Allocate a vector with the desired size | ||
read(&result[0],size);//Fill it with values | ||
return result; | ||
} | ||
|
||
std::string TimeoutSerial::readString(size_t size) | ||
{ | ||
string result(size,'\0');//Allocate a string with the desired size | ||
read(&result[0],size);//Fill it with values | ||
return result; | ||
} | ||
|
||
std::string TimeoutSerial::readStringUntil(const std::string& delim) | ||
{ | ||
// Note: if readData contains some previously read data, the call to | ||
// async_read_until (which is done in performReadSetup) correctly handles | ||
// it. If the data is enough it will also immediately call readCompleted() | ||
setupParameters=ReadSetupParameters(delim); | ||
performReadSetup(setupParameters); | ||
|
||
//For this code to work, there should always be a timeout, so the | ||
//request for no timeout is translated into a very long timeout | ||
if(timeout!=posix_time::seconds(0)) timer.expires_from_now(timeout); | ||
else timer.expires_from_now(posix_time::hours(100000)); | ||
|
||
timer.async_wait(boost::bind(&TimeoutSerial::timeoutExpired,this, | ||
asio::placeholders::error)); | ||
|
||
result=resultInProgress; | ||
bytesTransferred=0; | ||
for(;;) | ||
{ | ||
io.run_one(); | ||
switch(result) | ||
{ | ||
case resultSuccess: | ||
{ | ||
timer.cancel(); | ||
bytesTransferred-=delim.size();//Don't count delim | ||
istream is(&readData); | ||
string result(bytesTransferred,'\0');//Alloc string | ||
is.read(&result[0],bytesTransferred);//Fill values | ||
is.ignore(delim.size());//Remove delimiter from stream | ||
return result; | ||
} | ||
case resultTimeoutExpired: | ||
port.cancel(); | ||
throw(timeout_exception("Timeout expired")); | ||
case resultError: | ||
timer.cancel(); | ||
port.cancel(); | ||
throw(boost::system::system_error(boost::system::error_code(), | ||
"Error while reading")); | ||
//if resultInProgress remain in the loop | ||
} | ||
} | ||
} | ||
|
||
TimeoutSerial::~TimeoutSerial() {} | ||
|
||
void TimeoutSerial::performReadSetup(const ReadSetupParameters& param) | ||
{ | ||
if(param.fixedSize) | ||
{ | ||
asio::async_read(port,asio::buffer(param.data,param.size),boost::bind( | ||
&TimeoutSerial::readCompleted,this,asio::placeholders::error, | ||
asio::placeholders::bytes_transferred)); | ||
} else { | ||
asio::async_read_until(port,readData,param.delim,boost::bind( | ||
&TimeoutSerial::readCompleted,this,asio::placeholders::error, | ||
asio::placeholders::bytes_transferred)); | ||
} | ||
} | ||
|
||
void TimeoutSerial::timeoutExpired(const boost::system::error_code& error) | ||
{ | ||
if(!error && result==resultInProgress) result=resultTimeoutExpired; | ||
} | ||
|
||
void TimeoutSerial::readCompleted(const boost::system::error_code& error, | ||
const size_t bytesTransferred) | ||
{ | ||
if(!error) | ||
{ | ||
result=resultSuccess; | ||
this->bytesTransferred=bytesTransferred; | ||
return; | ||
} | ||
|
||
#ifdef __APPLE__ | ||
if(error.value()==45) | ||
{ | ||
//Bug on OS X, it might be necessary to repeat the setup | ||
//http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html | ||
performReadSetup(setupParameters); | ||
return; | ||
} | ||
#endif //__APPLE__ | ||
|
||
result=resultError; | ||
} |
Oops, something went wrong.