2012-01-15 02:06:38 -06:00
|
|
|
/* Copyright 2012 William Woodall and John Harrison */
|
2012-02-06 18:29:06 -06:00
|
|
|
#include <alloca.h>
|
2012-01-15 02:06:38 -06:00
|
|
|
|
2012-01-10 15:08:57 -06:00
|
|
|
#include "serial/serial.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include "serial/impl/win.h"
|
|
|
|
|
#else
|
|
|
|
|
#include "serial/impl/unix.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
using std::invalid_argument;
|
|
|
|
|
using std::min;
|
2012-01-12 16:44:19 -06:00
|
|
|
using std::numeric_limits;
|
2012-01-15 02:06:38 -06:00
|
|
|
using std::vector;
|
2012-01-12 16:44:19 -06:00
|
|
|
using std::size_t;
|
2012-01-15 02:06:38 -06:00
|
|
|
using std::string;
|
|
|
|
|
|
2012-01-11 17:48:31 -06:00
|
|
|
using serial::Serial;
|
2012-01-12 16:44:19 -06:00
|
|
|
using serial::SerialExecption;
|
|
|
|
|
using serial::IOException;
|
2012-01-11 17:48:31 -06:00
|
|
|
using serial::bytesize_t;
|
|
|
|
|
using serial::parity_t;
|
|
|
|
|
using serial::stopbits_t;
|
|
|
|
|
using serial::flowcontrol_t;
|
|
|
|
|
|
2012-02-03 01:43:42 -06:00
|
|
|
class Serial::ScopedReadLock {
|
|
|
|
|
public:
|
|
|
|
|
ScopedReadLock(SerialImpl *pimpl) : pimpl_(pimpl) {
|
|
|
|
|
this->pimpl_->readLock();
|
|
|
|
|
}
|
|
|
|
|
~ScopedReadLock() {
|
|
|
|
|
this->pimpl_->readUnlock();
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
SerialImpl *pimpl_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Serial::ScopedWriteLock {
|
|
|
|
|
public:
|
|
|
|
|
ScopedWriteLock(SerialImpl *pimpl) : pimpl_(pimpl) {
|
|
|
|
|
this->pimpl_->writeLock();
|
|
|
|
|
}
|
|
|
|
|
~ScopedWriteLock() {
|
|
|
|
|
this->pimpl_->writeUnlock();
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
SerialImpl *pimpl_;
|
|
|
|
|
};
|
2012-01-17 15:52:57 -06:00
|
|
|
|
2012-05-02 21:49:09 -05:00
|
|
|
Serial::Serial (const string &port, unsigned long baudrate, Timeout timeout,
|
2012-01-11 23:53:10 -06:00
|
|
|
bytesize_t bytesize, parity_t parity, stopbits_t stopbits,
|
2012-01-27 20:21:10 -06:00
|
|
|
flowcontrol_t flowcontrol)
|
|
|
|
|
: read_cache_("")
|
2012-01-10 15:08:57 -06:00
|
|
|
{
|
2012-05-02 00:45:23 -05:00
|
|
|
pimpl_ = new SerialImpl (port, baudrate, bytesize, parity,
|
2012-01-11 23:53:10 -06:00
|
|
|
stopbits, flowcontrol);
|
2012-05-02 21:49:09 -05:00
|
|
|
pimpl_->setTimeout(timeout);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::~Serial ()
|
|
|
|
|
{
|
2012-01-27 20:21:10 -06:00
|
|
|
delete pimpl_;
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::open ()
|
|
|
|
|
{
|
|
|
|
|
pimpl_->open ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::close ()
|
|
|
|
|
{
|
|
|
|
|
pimpl_->close ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-10 15:08:57 -06:00
|
|
|
bool
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::isOpen () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->isOpen ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::available ()
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->available ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-02-04 21:14:22 -06:00
|
|
|
size_t
|
|
|
|
|
Serial::read_ (unsigned char *buffer, size_t size)
|
|
|
|
|
{
|
|
|
|
|
return this->pimpl_->read (buffer, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
Serial::read (unsigned char *buffer, size_t size)
|
|
|
|
|
{
|
|
|
|
|
ScopedReadLock (this->pimpl_);
|
|
|
|
|
return this->pimpl_->read (buffer, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
Serial::read (std::vector<unsigned char> &buffer, size_t size)
|
|
|
|
|
{
|
|
|
|
|
ScopedReadLock (this->pimpl_);
|
|
|
|
|
unsigned char *buffer_ = new unsigned char[size];
|
|
|
|
|
size_t bytes_read = this->pimpl_->read (buffer_, size);
|
|
|
|
|
buffer.insert (buffer.end (), buffer_, buffer_+bytes_read);
|
|
|
|
|
delete[] buffer_;
|
|
|
|
|
return bytes_read;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
Serial::read (std::string &buffer, size_t size)
|
|
|
|
|
{
|
|
|
|
|
ScopedReadLock (this->pimpl_);
|
|
|
|
|
unsigned char *buffer_ = new unsigned char[size];
|
|
|
|
|
size_t bytes_read = this->pimpl_->read (buffer_, size);
|
|
|
|
|
buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read);
|
|
|
|
|
delete[] buffer_;
|
|
|
|
|
return bytes_read;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-11 17:48:31 -06:00
|
|
|
string
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::read (size_t size)
|
|
|
|
|
{
|
2012-02-04 21:14:22 -06:00
|
|
|
std::string buffer;
|
|
|
|
|
this->read (buffer, size);
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
Serial::readline (string &buffer, size_t size, string eol)
|
|
|
|
|
{
|
|
|
|
|
ScopedReadLock (this->pimpl_);
|
2012-02-06 18:22:14 -06:00
|
|
|
size_t eol_len = eol.length ();
|
|
|
|
|
unsigned char *buffer_ = static_cast<unsigned char*>
|
|
|
|
|
(alloca (size * sizeof (unsigned char)));
|
2012-02-04 21:14:22 -06:00
|
|
|
size_t read_so_far = 0;
|
|
|
|
|
while (true)
|
2012-01-15 02:06:38 -06:00
|
|
|
{
|
2012-02-06 18:22:14 -06:00
|
|
|
size_t bytes_read = this->read_ (buffer_ + read_so_far, 1);
|
2012-02-04 21:14:22 -06:00
|
|
|
read_so_far += bytes_read;
|
|
|
|
|
if (bytes_read == 0) {
|
|
|
|
|
break; // Timeout occured on reading 1 byte
|
|
|
|
|
}
|
2012-02-06 18:22:14 -06:00
|
|
|
if (string (reinterpret_cast<const char*>
|
|
|
|
|
(buffer_ + read_so_far - eol_len), eol_len) == eol) {
|
2012-02-04 21:14:22 -06:00
|
|
|
break; // EOL found
|
|
|
|
|
}
|
|
|
|
|
if (read_so_far == size) {
|
|
|
|
|
break; // Reached the maximum read length
|
2012-01-15 02:06:38 -06:00
|
|
|
}
|
|
|
|
|
}
|
2012-04-02 21:20:45 -05:00
|
|
|
buffer.append(reinterpret_cast<const char*> (buffer_), read_so_far);
|
2012-02-04 21:14:22 -06:00
|
|
|
return read_so_far;
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-01-11 21:53:26 -06:00
|
|
|
string
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::readline (size_t size, string eol)
|
|
|
|
|
{
|
2012-02-04 21:14:22 -06:00
|
|
|
std::string buffer;
|
|
|
|
|
this->readline (buffer, size, eol);
|
|
|
|
|
return buffer;
|
2012-01-11 21:53:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vector<string>
|
2012-02-04 21:14:22 -06:00
|
|
|
Serial::readlines (size_t size, string eol)
|
2012-01-15 02:06:38 -06:00
|
|
|
{
|
2012-02-04 21:14:22 -06:00
|
|
|
ScopedReadLock (this->pimpl_);
|
|
|
|
|
std::vector<std::string> lines;
|
2012-02-06 18:22:14 -06:00
|
|
|
size_t eol_len = eol.length ();
|
|
|
|
|
unsigned char *buffer_ = static_cast<unsigned char*>
|
|
|
|
|
(alloca (size * sizeof (unsigned char)));
|
2012-02-04 21:14:22 -06:00
|
|
|
size_t read_so_far = 0;
|
|
|
|
|
size_t start_of_line = 0;
|
|
|
|
|
while (read_so_far < size) {
|
|
|
|
|
size_t bytes_read = this->read_ (buffer_+read_so_far, 1);
|
|
|
|
|
read_so_far += bytes_read;
|
|
|
|
|
if (bytes_read == 0) {
|
|
|
|
|
if (start_of_line != read_so_far) {
|
2012-02-06 18:22:14 -06:00
|
|
|
lines.push_back (
|
|
|
|
|
string (reinterpret_cast<const char*> (buffer_ + start_of_line),
|
|
|
|
|
read_so_far - start_of_line));
|
2012-02-04 21:14:22 -06:00
|
|
|
}
|
|
|
|
|
break; // Timeout occured on reading 1 byte
|
|
|
|
|
}
|
2012-02-06 18:22:14 -06:00
|
|
|
if (string (reinterpret_cast<const char*>
|
|
|
|
|
(buffer_ + read_so_far - eol_len), eol_len) == eol) {
|
2012-02-04 21:14:22 -06:00
|
|
|
// EOL found
|
|
|
|
|
lines.push_back(
|
2012-02-06 18:22:14 -06:00
|
|
|
string(reinterpret_cast<const char*> (buffer_ + start_of_line),
|
|
|
|
|
read_so_far - start_of_line));
|
2012-02-04 21:14:22 -06:00
|
|
|
start_of_line = read_so_far;
|
|
|
|
|
}
|
|
|
|
|
if (read_so_far == size) {
|
|
|
|
|
if (start_of_line != read_so_far) {
|
|
|
|
|
lines.push_back(
|
2012-02-06 18:22:14 -06:00
|
|
|
string(reinterpret_cast<const char*> (buffer_ + start_of_line),
|
|
|
|
|
read_so_far - start_of_line));
|
2012-02-04 21:14:22 -06:00
|
|
|
}
|
|
|
|
|
break; // Reached the maximum read length
|
2012-01-11 21:53:26 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return lines;
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::write (const string &data)
|
|
|
|
|
{
|
2012-02-03 01:43:42 -06:00
|
|
|
ScopedWriteLock(this->pimpl_);
|
2012-01-15 02:06:38 -06:00
|
|
|
return pimpl_->write (data);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::setPort (const string &port)
|
|
|
|
|
{
|
2012-02-03 01:43:42 -06:00
|
|
|
ScopedReadLock(this->pimpl_);
|
|
|
|
|
ScopedWriteLock(this->pimpl_);
|
2012-02-06 18:22:14 -06:00
|
|
|
bool was_open = pimpl_->isOpen ();
|
2012-01-15 02:06:38 -06:00
|
|
|
if (was_open) close();
|
|
|
|
|
pimpl_->setPort (port);
|
2012-02-06 18:22:14 -06:00
|
|
|
if (was_open) open ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-01-11 17:48:31 -06:00
|
|
|
string
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::getPort () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getPort ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-05-02 21:49:09 -05:00
|
|
|
Serial::setTimeout (serial::Timeout &timeout)
|
2012-01-15 02:06:38 -06:00
|
|
|
{
|
|
|
|
|
pimpl_->setTimeout (timeout);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 21:49:09 -05:00
|
|
|
serial::Timeout
|
2012-01-10 15:08:57 -06:00
|
|
|
Serial::getTimeout () const {
|
2012-01-15 02:06:38 -06:00
|
|
|
return pimpl_->getTimeout ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::setBaudrate (unsigned long baudrate)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setBaudrate (baudrate);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-01-12 16:44:19 -06:00
|
|
|
unsigned long
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::getBaudrate () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getBaudrate ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::setBytesize (bytesize_t bytesize)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setBytesize (bytesize);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytesize_t
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::getBytesize () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getBytesize ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::setParity (parity_t parity)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setParity (parity);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parity_t
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::getParity () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getParity ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::setStopbits (stopbits_t stopbits)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setStopbits (stopbits);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stopbits_t
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::getStopbits () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getStopbits ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::setFlowcontrol (flowcontrol_t flowcontrol)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setFlowcontrol (flowcontrol);
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flowcontrol_t
|
2012-01-15 02:06:38 -06:00
|
|
|
Serial::getFlowcontrol () const
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getFlowcontrol ();
|
2012-01-10 15:08:57 -06:00
|
|
|
}
|
|
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::flush ()
|
|
|
|
|
{
|
2012-02-03 01:43:42 -06:00
|
|
|
ScopedReadLock(this->pimpl_);
|
|
|
|
|
ScopedWriteLock(this->pimpl_);
|
2012-01-15 02:06:38 -06:00
|
|
|
pimpl_->flush ();
|
2012-01-27 20:21:10 -06:00
|
|
|
read_cache_.clear ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::flushInput ()
|
|
|
|
|
{
|
2012-02-03 01:43:42 -06:00
|
|
|
ScopedReadLock(this->pimpl_);
|
2012-01-15 02:06:38 -06:00
|
|
|
pimpl_->flushInput ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::flushOutput ()
|
|
|
|
|
{
|
2012-02-03 01:43:42 -06:00
|
|
|
ScopedWriteLock(this->pimpl_);
|
2012-01-15 02:06:38 -06:00
|
|
|
pimpl_->flushOutput ();
|
2012-01-27 20:21:10 -06:00
|
|
|
read_cache_.clear ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::sendBreak (int duration)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->sendBreak (duration);
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::setBreak (bool level)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setBreak (level);
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::setRTS (bool level)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setRTS (level);
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
void Serial::setDTR (bool level)
|
|
|
|
|
{
|
|
|
|
|
pimpl_->setDTR (level);
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-05-02 00:45:23 -05:00
|
|
|
bool Serial::waitForChange()
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->waitForChange();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
bool Serial::getCTS ()
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getCTS ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
bool Serial::getDSR ()
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getDSR ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
bool Serial::getRI ()
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getRI ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|
2012-01-13 09:08:09 -06:00
|
|
|
|
2012-01-15 02:06:38 -06:00
|
|
|
bool Serial::getCD ()
|
|
|
|
|
{
|
|
|
|
|
return pimpl_->getCD ();
|
2012-01-12 12:46:08 -06:00
|
|
|
}
|