1
0
mirror of https://github.com/wjwwood/serial.git synced 2026-01-22 11:44:53 +08:00

Compare commits

...

41 Commits
1.2.1 ... main

Author SHA1 Message Date
Eric Fontaine
69e0372cf0
Move License text to separate LICENSE file (#261) 2022-03-08 16:16:57 -08:00
Maicol Castro
33e5a31ab7
Fix broken links (#244) 2021-06-10 15:15:44 -07:00
Robin Krens
ed9f89ca31
Add support for serial bluetooth ports on Linux (#237)
Added search blob /dev/rfcomm*. rfcomm* is a commonly used naming
convention for bluetooth ports on linux
2021-06-10 15:14:48 -07:00
Jacob Perron
9fc9e81fc1
Remove Boost dependency (#235)
It wasn't being used so there's no need to depend on it.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-06-10 15:14:20 -07:00
Matthias Behr
57f72772a9
Add EINTR handling to SerialImpl::write (#233)
EINTR can still happen on write. Don't throw the exception in that
case but retry.
In case of other errors add more details to the SerialException.
2021-06-10 15:13:58 -07:00
Atomie CHEN
a93fc844d9
Solve issue Custom Baudrate OSX #139 of original repo; inspired by PySerial source code and #57 of github.com/npat-efault/picocom, we need to set custom baudrate after calling tcsetattr; tested on macOS Mojave 10.14.4 (#218) 2021-06-10 14:57:40 -07:00
Hannes Kamecke
7439db1228
Fix windows com port prefix (#179)
The check in `_prefix_port_if_needed` does not work, as it's currently comparing the whole input string to the prefix. As a consequence, port strings will be prefixed, even if they're already prefixed. This commit changes the call to `wstring::compare` to use an overload that compares a substring of the input string only.
2021-06-10 14:57:28 -07:00
Chenchen
9e331e7977
fix invalid memory access when eol size >1 (#220)
Co-authored-by: chenguojun <chenguojun@yogorobot.com>
2021-06-10 14:49:29 -07:00
Sean Yen
cbcca7c837 Install serial library to a portable location. (#216) 2020-01-06 11:15:17 -08:00
bsbaliga
683e12d2f6 Fix memory leak when exception is thrown by impl classes in (#198)
Serial::read() vector and string variants.
2019-03-25 15:25:33 -07:00
William Woodall
fba8d81b5d
whitespace 2018-11-12 12:03:16 -06:00
William Woodall
2ef29d7b10
whitespace 2018-11-12 12:01:58 -06:00
William Woodall
5a354eaab7
reduce the number of jobs on travis (#172)
* reduce the number of jobs on travis

* update usage of pip due to changes in Homebrew

* update pip and ensure the right one is being used with an alias

* force reinstall pip to get `pip` on PATH

* use python2 explicitly to run catkin_make

* force use of python2 executable by catkin packages

* python!

* simpler

* how to which

* Update .travis.yml

* make tests and run_tests

* test results

* disable timer tests on macOS
2018-02-05 19:44:04 -08:00
Mike Purvis
bdba3a80ad Fix CMake warning for rt and pthread. (#165) 2018-01-18 17:25:29 -08:00
William Woodall
17e3223e68
remove references to no longer available uninstall command (#171) 2018-01-13 13:37:26 -08:00
William Woodall
764fab8b5e sublime project file updates 2018-01-13 13:19:48 -08:00
Ben Moyer
235a5f716d print GetLastError() result instead of errno (#154) 2018-01-13 12:16:50 -08:00
Ben Moyer
534141aa8f implement flushInput and flushOutput for windows (#153) 2018-01-13 12:15:36 -08:00
José Manuel Díez
ce085ce88c Problem: hardware flow control uses RTS_CONTROL_TOGGLE (#132)
RTS_CONTROL_HANDSHAKE raises RTS when there is space in the input
buffer; RTS_CONTROL_TOGGLE only raises RTS when bytes are available for
transmission.

Also replace numeric constants with symbolic constants.
2018-01-13 12:10:11 -08:00
Mike Purvis
d3713af096 Support 500kbps serial ports. (#167) 2018-01-09 07:22:43 -08:00
rhd
827c4a784d Fix issue with write() and a timeout of 0. (#137)
* Fix issue with write() and a timeout of 0.

* fix up style
2017-01-20 17:34:49 -08:00
Stephane Poirier
771e62c220 Update documentation (#140)
* Fix typo and missing dependency in README

* [docs] Update docs: fix deprecation warnings + add missing deps to README
2017-01-20 15:29:03 -08:00
aleksey-sergey
02dfff7883 fixing unix timeouts handling ("timer_tests.short_interval" failure) (#147) 2016-11-28 17:38:53 -08:00
aleksey-sergey
4d69fb2e41 fix timeouts handling on Unix systems (#142)
fixed "singed long" overflow that took place on attempt
to use ~3000ms or bigger timeouts on Unix systems
2016-11-28 14:06:00 -08:00
dontsovcmc
c16faab6ea resource leak if exception in SerialImpl constructor (#146) 2016-11-21 14:48:07 -08:00
Christopher Baker
d76b7d6b7f Const corrections. (#141) 2016-10-17 13:54:11 +09:00
William Woodall
2d416f1560 Merge pull request #118 from Rimco/patch-1
Updated serial.cc for FreeBSD 9 compatibility.
2015-12-02 09:06:25 -08:00
Rimco
22dce33fa4 Updated serial.cc for FreeBSD 9 compatibility. 2015-11-26 22:15:48 +01:00
William Woodall
e12d81eadf Merge pull request #116 from pao/patch-1
Use CLOCK_MONOTONIC (Linux)/SYSTEM_CLOCK (OS X) to time select()
2015-11-10 15:35:05 -08:00
Patrick O'Leary
c5b4bbd181 on OS X, use SYSTEM_CLOCK, not CALENDAR_CLOCK
Analogously to using `CLOCK_MONOTONIC` on Linux to time events in favor of `CLOCK_REALTIME`, `SYSTEM_CLOCK` should be used in favor of `CALENDAR_CLOCK` on OS X.

Ref: http://stackoverflow.com/questions/11680461/monotonic-clock-on-osx
2015-11-10 17:28:45 -06:00
Patrick O'Leary
98f1c31e81 on Linux, use CLOCK_MONOTONIC for clock_gettime()
On Linux systems which are being driven by an external time source (NTP or PTP), it is possible that time appears to slew in reverse under `CLOCK_REALTIME`. Since the timer function is used to time durations of events (calls to `select()`), it is better to use `CLOCK_MONOTONIC`, which isn't subject to slewing.
2015-11-10 09:40:30 -06:00
William Woodall
ef7f77d411 Merge pull request #113 from vladimirgamalian/patch-1
Comment unreferenced formal parameters
2015-09-27 14:14:03 -07:00
Vladimir Gamalian
402657574c Comment unreferenced formal parameter
Fix warning from static analysis tools.
2015-09-27 19:41:56 +07:00
William Woodall
a81087ec85 Merge pull request #112 from linquize/vs2015
Support VS2015
2015-09-23 14:35:04 -07:00
Linquize
9b80fc3fbf Can use the toolsets from Visual Studio 2010, 2012, 2013, 2015 2015-09-22 21:45:43 +08:00
William Woodall
c57285f30a Merge pull request #106 from ramirahikkala/master
AdditionalIncludeDirectories must be relative for project not solution
2015-08-14 10:11:13 -07:00
Rami
cd5053cb32 AdditionalIncludeDirectories must be relative for project not solution
Fixes #105

Signed-off-by: Rami <rami.rahikkala@jotautomation.com>
2015-08-14 08:37:27 +03:00
William Woodall
6144d579af Merge pull request #103 from drummist180/master
Fix include directory paths in Visual Studio projects.
2015-07-21 16:02:36 -07:00
Brandon Morton
1580f10d39 Fix include directory paths in Visual Studio projects.
Remove previously ignored *.user file.
2015-07-16 19:17:52 -07:00
William Woodall
99e57e633c Merge pull request #98 from wjwwood/fix_issue_97
fix warning on Windows
2015-04-27 15:20:05 -07:00
William Woodall
b8320d31a7 fix warning on Windows 2015-04-27 14:44:16 -07:00
19 changed files with 1776 additions and 1016 deletions

View File

@ -2,11 +2,9 @@ os:
- linux - linux
- osx - osx
language: cpp language: cpp
compiler:
- gcc
- clang
install: install:
- make install_deps - make install_deps
- source setup.bash - source setup.bash
script: script:
- make && make test - mkdir build && cd build && cmake .. -DPYTHON_EXECUTABLE=$(which python2) && make && make tests && make run_tests
- catkin_test_results .

View File

@ -11,6 +11,8 @@ endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
# If Linux, add rt and pthread # If Linux, add rt and pthread
set(rt_LIBRARIES rt)
set(pthread_LIBRARIES pthread)
catkin_package( catkin_package(
LIBRARIES ${PROJECT_NAME} LIBRARIES ${PROJECT_NAME}
INCLUDE_DIRS include INCLUDE_DIRS include
@ -66,6 +68,7 @@ include_directories(include)
install(TARGETS ${PROJECT_NAME} install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
) )
## Install headers ## Install headers

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
Copyright (c) 2012 William Woodall, John Harrison
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -8,14 +8,17 @@ ifeq ($(UNAME),Darwin)
brew tap ros/deps brew tap ros/deps
brew update brew update
brew outdated boost || brew upgrade boost || brew install boost brew outdated boost || brew upgrade boost || brew install boost
sudo pip install rosinstall_generator wstool rosdep empy catkin_pkg brew outdated python || brew upgrade python || brew install python
sudo rosdep init sudo -H python2 -m pip install -U pip setuptools
sudo -H python2 -m pip install --force-reinstall --no-deps -U pip
sudo -H python2 -m pip install rosinstall_generator wstool rosdep empy catkin_pkg
sudo -H rosdep init
rosdep update rosdep update
mkdir catkin_ws mkdir catkin_ws
cd catkin_ws && rosinstall_generator catkin --rosdistro hydro --tar > catkin.rosinstall cd catkin_ws && rosinstall_generator catkin --rosdistro hydro --tar > catkin.rosinstall
cd catkin_ws && wstool init src catkin.rosinstall cd catkin_ws && wstool init src catkin.rosinstall
cd catkin_ws && rosdep install --from-paths src --ignore-src -y cd catkin_ws && rosdep install --from-paths src --ignore-src -y
cd catkin_ws && ./src/catkin/bin/catkin_make install cd catkin_ws && python2 ./src/catkin/bin/catkin_make -DPYTHON_EXECUTABLE=`which python2` install
echo "source catkin_ws/install/setup.bash" > setup.bash echo "source catkin_ws/install/setup.bash" > setup.bash
else else
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu precise main" > /etc/apt/sources.list.d/ros-latest.list' sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu precise main" > /etc/apt/sources.list.d/ros-latest.list'
@ -28,9 +31,6 @@ endif
install: install:
cd build && make install cd build && make install
uninstall:
cd build && make uninstall
serial: serial:
@mkdir -p build @mkdir -p build
cd build && cmake $(CMAKE_FLAGS) .. cd build && cmake $(CMAKE_FLAGS) ..

View File

@ -10,18 +10,23 @@ Serial is a class that provides the basic interface common to serial libraries (
### Documentation ### Documentation
Website: http://wjwwood.github.com/serial/ Website: http://wjwwood.github.io/serial/
API Documentation: http://wjwwood.github.com/serial/doc/1.1.0/index.html API Documentation: http://wjwwood.github.io/serial/doc/1.1.0/index.html
### Dependencies ### Dependencies
Required:
* [catkin](http://www.ros.org/wiki/catkin) - cmake and Python based buildsystem * [catkin](http://www.ros.org/wiki/catkin) - cmake and Python based buildsystem
* [cmake](http://www.cmake.org) - buildsystem * [cmake](http://www.cmake.org) - buildsystem
* [Python](http://www.python.org) - scripting language * [Python](http://www.python.org) - scripting language
* [empy](http://www.alcyone.com/pyos/empy/) - Python templating library * [empy](http://www.alcyone.com/pyos/empy/) - Python templating library
* [catkin_pkg](http://pypi.python.org/pypi/catkin_pkg/) - Runtime Python library for catkin * [catkin_pkg](http://pypi.python.org/pypi/catkin_pkg/) - Runtime Python library for catkin
Optional (for documentation):
* [Doxygen](http://www.doxygen.org/) - Documentation generation tool
* [graphviz](http://www.graphviz.org/) - Graph visualization software
### Install ### Install
Get the code: Get the code:
@ -38,27 +43,15 @@ Build and run the tests:
Build the documentation: Build the documentation:
make docs make doc
Install: Install:
make install make install
Uninstall:
make uninstall
### License ### License
The MIT License [The MIT License](LICENSE)
Copyright (c) 2012 William Woodall, John Harrison
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### Authors ### Authors

File diff suppressed because it is too large Load Diff

View File

@ -55,10 +55,4 @@ To install simply:
sudo make install sudo make install
</pre> </pre>
To uninstall simply:
<pre>
sudo make uninstall
</pre>
*/ */

View File

@ -450,6 +450,8 @@ public:
* reading or writing is complete, when a timeout occurs, or when an * reading or writing is complete, when a timeout occurs, or when an
* exception occurs. * exception occurs.
* *
* A timeout of 0 enables non-blocking mode.
*
* \param timeout A serial::Timeout struct containing the inter byte * \param timeout A serial::Timeout struct containing the inter byte
* timeout, and the read and write timeout constants and multipliers. * timeout, and the read and write timeout constants and multipliers.
* *
@ -486,7 +488,7 @@ public:
* 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000, * 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000,
* 57600, 115200 * 57600, 115200
* Some other baudrates that are supported by some comports: * Some other baudrates that are supported by some comports:
* 128000, 153600, 230400, 256000, 460800, 921600 * 128000, 153600, 230400, 256000, 460800, 500000, 921600
* *
* \param baudrate An integer that sets the baud rate for the serial port. * \param baudrate An integer that sets the baud rate for the serial port.
* *
@ -717,7 +719,7 @@ public:
virtual ~IOException() throw() {} virtual ~IOException() throw() {}
IOException (const IOException& other) : line_(other.line_), e_what_(other.e_what_), errno_(other.errno_) {} IOException (const IOException& other) : line_(other.line_), e_what_(other.e_what_), errno_(other.errno_) {}
int getErrorNumber () { return errno_; } int getErrorNumber () const { return errno_; }
virtual const char* what () const throw () { virtual const char* what () const throw () {
return e_what_.c_str(); return e_what_.c_str();

View File

@ -3,7 +3,9 @@
<name>serial</name> <name>serial</name>
<version>1.2.1</version> <version>1.2.1</version>
<description> <description>
Serial is a cross-platform, simple to use library for using serial ports on computers. This library provides a C++, object oriented interface for interacting with RS-232 like devices on Linux and Windows. Serial is a cross-platform, simple to use library for using serial ports on computers.
This library provides a C++, object oriented interface for interacting with RS-232
like devices on Linux and Windows.
</description> </description>
<maintainer email="william@osrfoundation.org">William Woodall</maintainer> <maintainer email="william@osrfoundation.org">William Woodall</maintainer>
@ -19,6 +21,4 @@
<buildtool_depend>catkin</buildtool_depend> <buildtool_depend>catkin</buildtool_depend>
<test_depend>boost</test_depend>
</package> </package>

View File

@ -11,14 +11,12 @@
{ {
"sublimeclang_options": "sublimeclang_options":
[ [
"-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
"-I/usr/local/include",
"-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include",
"-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
"-I/usr/include", "-I/usr/include",
"-I/usr/local/include",
"-I${folder:${project_path:serial.sublime-project}}/include", "-I${folder:${project_path:serial.sublime-project}}/include",
"-I/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1",
"-I/usr/local/include",
"-I/Library/Developer/CommandLineTools/usr/bin/../lib/clang/6.1.0/include",
"-I/Library/Developer/CommandLineTools/usr/include",
"-I/usr/include"
] ]
} }
} }

View File

@ -305,6 +305,7 @@ serial::list_ports()
search_globs.push_back("/dev/ttyUSB*"); search_globs.push_back("/dev/ttyUSB*");
search_globs.push_back("/dev/tty.*"); search_globs.push_back("/dev/tty.*");
search_globs.push_back("/dev/cu.*"); search_globs.push_back("/dev/cu.*");
search_globs.push_back("/dev/rfcomm*");
vector<string> devices_found = glob( search_globs ); vector<string> devices_found = glob( search_globs );

View File

@ -62,7 +62,7 @@ MillisecondTimer::MillisecondTimer (const uint32_t millis)
int64_t tv_nsec = expiry.tv_nsec + (millis * 1e6); int64_t tv_nsec = expiry.tv_nsec + (millis * 1e6);
if (tv_nsec >= 1e9) { if (tv_nsec >= 1e9) {
int64_t sec_diff = tv_nsec / static_cast<int> (1e9); int64_t sec_diff = tv_nsec / static_cast<int> (1e9);
expiry.tv_nsec = tv_nsec - static_cast<int> (1e9 * sec_diff); expiry.tv_nsec = tv_nsec % static_cast<int>(1e9);
expiry.tv_sec += sec_diff; expiry.tv_sec += sec_diff;
} else { } else {
expiry.tv_nsec = tv_nsec; expiry.tv_nsec = tv_nsec;
@ -85,13 +85,13 @@ MillisecondTimer::timespec_now ()
# ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time # ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
clock_serv_t cclock; clock_serv_t cclock;
mach_timespec_t mts; mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
clock_get_time(cclock, &mts); clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock); mach_port_deallocate(mach_task_self(), cclock);
time.tv_sec = mts.tv_sec; time.tv_sec = mts.tv_sec;
time.tv_nsec = mts.tv_nsec; time.tv_nsec = mts.tv_nsec;
# else # else
clock_gettime(CLOCK_REALTIME, &time); clock_gettime(CLOCK_MONOTONIC, &time);
# endif # endif
return time; return time;
} }
@ -269,6 +269,9 @@ Serial::SerialImpl::reconfigurePort ()
#ifdef B460800 #ifdef B460800
case 460800: baud = B460800; break; case 460800: baud = B460800; break;
#endif #endif
#ifdef B500000
case 500000: baud = B500000; break;
#endif
#ifdef B576000 #ifdef B576000
case 576000: baud = B576000; break; case 576000: baud = B576000; break;
#endif #endif
@ -301,36 +304,6 @@ Serial::SerialImpl::reconfigurePort ()
#endif #endif
default: default:
custom_baud = true; custom_baud = true;
// OS X support
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
// Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
// other than those specified by POSIX. The driver for the underlying serial hardware
// ultimately determines which baud rates can be used. This ioctl sets both the input
// and output speed.
speed_t new_baud = static_cast<speed_t> (baudrate_);
if (-1 == ioctl (fd_, IOSSIOSPEED, &new_baud, 1)) {
THROW (IOException, errno);
}
// Linux Support
#elif defined(__linux__) && defined (TIOCSSERIAL)
struct serial_struct ser;
if (-1 == ioctl (fd_, TIOCGSERIAL, &ser)) {
THROW (IOException, errno);
}
// set custom divisor
ser.custom_divisor = ser.baud_base / static_cast<int> (baudrate_);
// update flags
ser.flags &= ~ASYNC_SPD_MASK;
ser.flags |= ASYNC_SPD_CUST;
if (-1 == ioctl (fd_, TIOCSSERIAL, &ser)) {
THROW (IOException, errno);
}
#else
throw invalid_argument ("OS does not currently support custom bauds");
#endif
} }
if (custom_baud == false) { if (custom_baud == false) {
#ifdef _BSD_SOURCE #ifdef _BSD_SOURCE
@ -440,6 +413,41 @@ Serial::SerialImpl::reconfigurePort ()
// activate settings // activate settings
::tcsetattr (fd_, TCSANOW, &options); ::tcsetattr (fd_, TCSANOW, &options);
// apply custom baud rate, if any
if (custom_baud == true) {
// OS X support
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
// Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
// other than those specified by POSIX. The driver for the underlying serial hardware
// ultimately determines which baud rates can be used. This ioctl sets both the input
// and output speed.
speed_t new_baud = static_cast<speed_t> (baudrate_);
// PySerial uses IOSSIOSPEED=0x80045402
if (-1 == ioctl (fd_, IOSSIOSPEED, &new_baud, 1)) {
THROW (IOException, errno);
}
// Linux Support
#elif defined(__linux__) && defined (TIOCSSERIAL)
struct serial_struct ser;
if (-1 == ioctl (fd_, TIOCGSERIAL, &ser)) {
THROW (IOException, errno);
}
// set custom divisor
ser.custom_divisor = ser.baud_base / static_cast<int> (baudrate_);
// update flags
ser.flags &= ~ASYNC_SPD_MASK;
ser.flags |= ASYNC_SPD_CUST;
if (-1 == ioctl (fd_, TIOCSSERIAL, &ser)) {
THROW (IOException, errno);
}
#else
throw invalid_argument ("OS does not currently support custom bauds");
#endif
}
// Update byte_time_ based on the new settings. // Update byte_time_ based on the new settings.
uint32_t bit_time_ns = 1e9 / baudrate_; uint32_t bit_time_ns = 1e9 / baudrate_;
byte_time_ns_ = bit_time_ns * (1 + bytesize_ + parity_ + stopbits_); byte_time_ns_ = bit_time_ns * (1 + bytesize_ + parity_ + stopbits_);
@ -617,12 +625,17 @@ Serial::SerialImpl::write (const uint8_t *data, size_t length)
total_timeout_ms += timeout_.write_timeout_multiplier * static_cast<long> (length); total_timeout_ms += timeout_.write_timeout_multiplier * static_cast<long> (length);
MillisecondTimer total_timeout(total_timeout_ms); MillisecondTimer total_timeout(total_timeout_ms);
bool first_iteration = true;
while (bytes_written < length) { while (bytes_written < length) {
int64_t timeout_remaining_ms = total_timeout.remaining(); int64_t timeout_remaining_ms = total_timeout.remaining();
if (timeout_remaining_ms <= 0) { // Only consider the timeout if it's not the first iteration of the loop
// otherwise a timeout of 0 won't be allowed through
if (!first_iteration && (timeout_remaining_ms <= 0)) {
// Timed out // Timed out
break; break;
} }
first_iteration = false;
timespec timeout(timespec_from_ms(timeout_remaining_ms)); timespec timeout(timespec_from_ms(timeout_remaining_ms));
FD_ZERO (&writefds); FD_ZERO (&writefds);
@ -652,14 +665,27 @@ Serial::SerialImpl::write (const uint8_t *data, size_t length)
// This will write some // This will write some
ssize_t bytes_written_now = ssize_t bytes_written_now =
::write (fd_, data + bytes_written, length - bytes_written); ::write (fd_, data + bytes_written, length - bytes_written);
// even though pselect returned readiness the call might still be
// interrupted. In that case simply retry.
if (bytes_written_now == -1 && errno == EINTR) {
continue;
}
// write should always return some data as select reported it was // write should always return some data as select reported it was
// ready to write when we get to this point. // ready to write when we get to this point.
if (bytes_written_now < 1) { if (bytes_written_now < 1) {
// Disconnected devices, at least on Linux, show the // Disconnected devices, at least on Linux, show the
// behavior that they are always ready to write immediately // behavior that they are always ready to write immediately
// but writing returns nothing. // but writing returns nothing.
throw SerialException ("device reports readiness to write but " std::stringstream strs;
"returned no data (device disconnected?)"); strs << "device reports readiness to write but "
"returned no data (device disconnected?)";
strs << " errno=" << errno;
strs << " bytes_written_now= " << bytes_written_now;
strs << " bytes_written=" << bytes_written;
strs << " length=" << length;
throw SerialException(strs.str().c_str());
} }
// Update bytes_written // Update bytes_written
bytes_written += static_cast<size_t> (bytes_written_now); bytes_written += static_cast<size_t> (bytes_written_now);

View File

@ -24,10 +24,11 @@ inline wstring
_prefix_port_if_needed(const wstring &input) _prefix_port_if_needed(const wstring &input)
{ {
static wstring windows_com_port_prefix = L"\\\\.\\"; static wstring windows_com_port_prefix = L"\\\\.\\";
if (input.compare(windows_com_port_prefix) != 0) if (input.compare(0, windows_com_port_prefix.size(), windows_com_port_prefix) != 0)
{ {
return windows_com_port_prefix + input; return windows_com_port_prefix + input;
} }
return input;
} }
Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate, Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
@ -38,10 +39,10 @@ Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
baudrate_ (baudrate), parity_ (parity), baudrate_ (baudrate), parity_ (parity),
bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol) bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
{ {
read_mutex = CreateMutex(NULL, false, NULL);
write_mutex = CreateMutex(NULL, false, NULL);
if (port_.empty () == false) if (port_.empty () == false)
open (); open ();
read_mutex = CreateMutex(NULL, false, NULL);
write_mutex = CreateMutex(NULL, false, NULL);
} }
Serial::SerialImpl::~SerialImpl () Serial::SerialImpl::~SerialImpl ()
@ -73,15 +74,15 @@ Serial::SerialImpl::open ()
0); 0);
if (fd_ == INVALID_HANDLE_VALUE) { if (fd_ == INVALID_HANDLE_VALUE) {
DWORD errno_ = GetLastError(); DWORD create_file_err = GetLastError();
stringstream ss; stringstream ss;
switch (errno_) { switch (create_file_err) {
case ERROR_FILE_NOT_FOUND: case ERROR_FILE_NOT_FOUND:
// Use this->getPort to convert to a std::string // Use this->getPort to convert to a std::string
ss << "Specified port, " << this->getPort() << ", does not exist."; ss << "Specified port, " << this->getPort() << ", does not exist.";
THROW (IOException, ss.str().c_str()); THROW (IOException, ss.str().c_str());
default: default:
ss << "Unknown error opening the serial port: " << errno; ss << "Unknown error opening the serial port: " << create_file_err;
THROW (IOException, ss.str().c_str()); THROW (IOException, ss.str().c_str());
} }
} }
@ -238,19 +239,19 @@ Serial::SerialImpl::reconfigurePort ()
// setup flowcontrol // setup flowcontrol
if (flowcontrol_ == flowcontrol_none) { if (flowcontrol_ == flowcontrol_none) {
dcbSerialParams.fOutxCtsFlow = false; dcbSerialParams.fOutxCtsFlow = false;
dcbSerialParams.fRtsControl = 0x00; dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.fOutX = false; dcbSerialParams.fOutX = false;
dcbSerialParams.fInX = false; dcbSerialParams.fInX = false;
} }
if (flowcontrol_ == flowcontrol_software) { if (flowcontrol_ == flowcontrol_software) {
dcbSerialParams.fOutxCtsFlow = false; dcbSerialParams.fOutxCtsFlow = false;
dcbSerialParams.fRtsControl = 0x00; dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.fOutX = true; dcbSerialParams.fOutX = true;
dcbSerialParams.fInX = true; dcbSerialParams.fInX = true;
} }
if (flowcontrol_ == flowcontrol_hardware) { if (flowcontrol_ == flowcontrol_hardware) {
dcbSerialParams.fOutxCtsFlow = true; dcbSerialParams.fOutxCtsFlow = true;
dcbSerialParams.fRtsControl = 0x03; dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcbSerialParams.fOutX = false; dcbSerialParams.fOutX = false;
dcbSerialParams.fInX = false; dcbSerialParams.fInX = false;
} }
@ -314,14 +315,14 @@ Serial::SerialImpl::available ()
} }
bool bool
Serial::SerialImpl::waitReadable (uint32_t timeout) Serial::SerialImpl::waitReadable (uint32_t /*timeout*/)
{ {
THROW (IOException, "waitReadable is not implemented on Windows."); THROW (IOException, "waitReadable is not implemented on Windows.");
return false; return false;
} }
void void
Serial::SerialImpl::waitByteTimes (size_t count) Serial::SerialImpl::waitByteTimes (size_t /*count*/)
{ {
THROW (IOException, "waitByteTimes is not implemented on Windows."); THROW (IOException, "waitByteTimes is not implemented on Windows.");
} }
@ -470,17 +471,23 @@ Serial::SerialImpl::flush ()
void void
Serial::SerialImpl::flushInput () Serial::SerialImpl::flushInput ()
{ {
THROW (IOException, "flushInput is not supported on Windows."); if (is_open_ == false) {
throw PortNotOpenedException("Serial::flushInput");
}
PurgeComm(fd_, PURGE_RXCLEAR);
} }
void void
Serial::SerialImpl::flushOutput () Serial::SerialImpl::flushOutput ()
{ {
THROW (IOException, "flushOutput is not supported on Windows."); if (is_open_ == false) {
throw PortNotOpenedException("Serial::flushOutput");
}
PurgeComm(fd_, PURGE_TXCLEAR);
} }
void void
Serial::SerialImpl::sendBreak (int duration) Serial::SerialImpl::sendBreak (int /*duration*/)
{ {
THROW (IOException, "sendBreak is not supported on Windows."); THROW (IOException, "sendBreak is not supported on Windows.");
} }

View File

@ -1,7 +1,7 @@
/* Copyright 2012 William Woodall and John Harrison */ /* Copyright 2012 William Woodall and John Harrison */
#include <algorithm> #include <algorithm>
#if !defined(_WIN32) && !defined(__OpenBSD__) #if !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
# include <alloca.h> # include <alloca.h>
#endif #endif
@ -132,7 +132,16 @@ Serial::read (std::vector<uint8_t> &buffer, size_t size)
{ {
ScopedReadLock lock(this->pimpl_); ScopedReadLock lock(this->pimpl_);
uint8_t *buffer_ = new uint8_t[size]; uint8_t *buffer_ = new uint8_t[size];
size_t bytes_read = this->pimpl_->read (buffer_, size); size_t bytes_read = 0;
try {
bytes_read = this->pimpl_->read (buffer_, size);
}
catch (const std::exception &e) {
delete[] buffer_;
throw;
}
buffer.insert (buffer.end (), buffer_, buffer_+bytes_read); buffer.insert (buffer.end (), buffer_, buffer_+bytes_read);
delete[] buffer_; delete[] buffer_;
return bytes_read; return bytes_read;
@ -143,7 +152,14 @@ Serial::read (std::string &buffer, size_t size)
{ {
ScopedReadLock lock(this->pimpl_); ScopedReadLock lock(this->pimpl_);
uint8_t *buffer_ = new uint8_t[size]; uint8_t *buffer_ = new uint8_t[size];
size_t bytes_read = this->pimpl_->read (buffer_, size); size_t bytes_read = 0;
try {
bytes_read = this->pimpl_->read (buffer_, size);
}
catch (const std::exception &e) {
delete[] buffer_;
throw;
}
buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read); buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read);
delete[] buffer_; delete[] buffer_;
return bytes_read; return bytes_read;
@ -172,6 +188,7 @@ Serial::readline (string &buffer, size_t size, string eol)
if (bytes_read == 0) { if (bytes_read == 0) {
break; // Timeout occured on reading 1 byte break; // Timeout occured on reading 1 byte
} }
if(read_so_far < eol_len) continue;
if (string (reinterpret_cast<const char*> if (string (reinterpret_cast<const char*>
(buffer_ + read_so_far - eol_len), eol_len) == eol) { (buffer_ + read_so_far - eol_len), eol_len) == eol) {
break; // EOL found break; // EOL found
@ -213,6 +230,7 @@ Serial::readlines (size_t size, string eol)
} }
break; // Timeout occured on reading 1 byte break; // Timeout occured on reading 1 byte
} }
if(read_so_far < eol_len) continue;
if (string (reinterpret_cast<const char*> if (string (reinterpret_cast<const char*>
(buffer_ + read_so_far - eol_len), eol_len) == eol) { (buffer_ + read_so_far - eol_len), eol_len) == eol) {
// EOL found // EOL found

View File

@ -1,10 +1,12 @@
if(UNIX) if(UNIX)
catkin_add_gtest(${PROJECT_NAME}-test unix_serial_tests.cc) catkin_add_gtest(${PROJECT_NAME}-test unix_serial_tests.cc)
target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME} ${Boost_LIBRARIES}) target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
if(NOT APPLE) if(NOT APPLE)
target_link_libraries(${PROJECT_NAME}-test util) target_link_libraries(${PROJECT_NAME}-test util)
endif() endif()
if(NOT APPLE) # these tests are unreliable on macOS
catkin_add_gtest(${PROJECT_NAME}-test-timer unit/unix_timer_tests.cc) catkin_add_gtest(${PROJECT_NAME}-test-timer unit/unix_timer_tests.cc)
target_link_libraries(${PROJECT_NAME}-test-timer ${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME}-test-timer ${PROJECT_NAME})
endif()
endif() endif()

View File

@ -20,8 +20,6 @@ void loop()
#include <string> #include <string>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <boost/bind.hpp>
// Use FRIEND_TEST... its not as nasty, thats what friends are for // Use FRIEND_TEST... its not as nasty, thats what friends are for
// // OMG this is so nasty... // // OMG this is so nasty...
// #define private public // #define private public

View File

@ -23,6 +23,7 @@
<RootNamespace>serial</RootNamespace> <RootNamespace>serial</RootNamespace>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '14.0'">v140_xp</PlatformToolset>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '12.0'">v120_xp</PlatformToolset> <PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '12.0'">v120_xp</PlatformToolset>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '11.0'">v110_xp</PlatformToolset> <PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '11.0'">v110_xp</PlatformToolset>
</PropertyGroup> </PropertyGroup>
@ -70,7 +71,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\serial\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -84,7 +85,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\serial\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -100,7 +101,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\..\serial\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -118,7 +119,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\..\serial\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>

View File

@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

View File

@ -23,6 +23,7 @@
<RootNamespace>test_serial</RootNamespace> <RootNamespace>test_serial</RootNamespace>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '14.0'">v140_xp</PlatformToolset>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '12.0'">v120_xp</PlatformToolset> <PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '12.0'">v120_xp</PlatformToolset>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '11.0'">v110_xp</PlatformToolset> <PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VisualStudioVersion)' == '11.0'">v110_xp</PlatformToolset>
</PropertyGroup> </PropertyGroup>
@ -70,7 +71,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\serial\include</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -81,7 +82,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\serial\include</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -94,7 +95,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\..\serial\include</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -109,7 +110,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\..\serial\include</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..\..\include</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>