├── .gitignore ├── .vimrc ├── .ycm_extra_conf.py ├── AUTHORS ├── CMakeLists.txt ├── ChangeLog ├── INSTALL ├── LICENSE.txt ├── LibSerial.sublime-project ├── Makefile.am ├── Makefile.dist ├── NEWS ├── README ├── README.md ├── compile.sh ├── configure.ac ├── dockerfiles ├── centos │ └── 7 │ │ └── Dockerfile ├── debian │ └── buster │ │ └── Dockerfile └── ubuntu │ ├── 16.04 │ └── Dockerfile │ └── 18.04 │ └── Dockerfile ├── docs ├── .cvsignore ├── MAINPAGE.md ├── Makefile.am ├── UML │ ├── .cvsignore │ ├── Makefile.am │ └── libserial_class_diagram.dia └── user_manual │ ├── Makefile.am │ ├── api_documentation.rst │ ├── conf.py │ ├── description.rst │ ├── design_documentation.rst │ ├── download.rst │ ├── feature_summary.rst │ ├── index.rst │ ├── install.rst │ ├── links.rst │ └── tutorial.rst ├── doxygen.conf.in ├── examples ├── .cvsignore ├── CMakeLists.txt ├── Makefile.am ├── TestFile.txt ├── example_project │ ├── CMakeLists.txt │ ├── compile.sh │ └── example_project.cpp ├── main_page_example.cpp ├── serial_port_read.cpp ├── serial_port_read_write.cpp ├── serial_port_write.cpp ├── serial_stream_read.cpp ├── serial_stream_read_write.cpp └── serial_stream_write.cpp ├── gtest.sh ├── libserial.pc.in ├── libserial.spec.in ├── m4 ├── ax_cxx_compile_stdcxx.m4 └── ax_cxx_compile_stdcxx_11.m4 ├── packaging ├── CMakeLists.txt └── package_desc.txt ├── sip ├── CMakeLists.txt ├── Makefile.am ├── SerialPort.sip ├── SerialPortConstants.sip ├── configure.py.in ├── exception.sip ├── iosbase.sip ├── libserial.sip ├── recv_test.py ├── send_test.py ├── stdexcept.sip ├── string.sip ├── test_control_lines.py └── vector.sip ├── src ├── .cvsignore ├── CMakeLists.txt ├── Makefile.am ├── SerialPort.cpp ├── SerialStream.cpp ├── SerialStreamBuf.cpp └── libserial │ ├── Makefile.am │ ├── SerialPort.h │ ├── SerialPortConstants.h │ ├── SerialStream.h │ └── SerialStreamBuf.h ├── stamp-h.in ├── sync_docs.sh └── test ├── CMakeLists.txt ├── Makefile.am ├── MultiThreadUnitTests.cpp ├── MultiThreadUnitTests.h ├── SerialPortUnitTests.cpp ├── SerialPortUnitTests.h ├── SerialStreamUnitTests.cpp ├── SerialStreamUnitTests.h ├── UnitTests.cpp ├── UnitTests.h └── unit_tests.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # backup files 2 | *~ 3 | \#* 4 | .\#* 5 | *.swp 6 | *.bak 7 | *.o 8 | *.lo 9 | *.la 10 | 11 | # build directories 12 | build 13 | 14 | # lincense files 15 | COPYING 16 | 17 | # tag files 18 | GPATH 19 | GRTAGS 20 | GTAGS 21 | TAGS 22 | 23 | # Data points to plot w/ gnuplot 24 | *.dat 25 | 26 | gtest 27 | 28 | # Sublime workspace 29 | *.sublime-workspace 30 | 31 | cmake_install.cmake 32 | CMakeCache.txt 33 | CMakeFiles 34 | 35 | .deps 36 | .libs 37 | 38 | # Docs 39 | docs/doxygen/ 40 | docs/html/ 41 | docs/.doctrees/ 42 | 43 | # Files resulting from make build 44 | Makefile 45 | Makefile.in 46 | aclocal.m4 47 | autom4te.cache 48 | compile 49 | config.guess 50 | config.h 51 | config.h.in 52 | config.log 53 | config.status 54 | config.sub 55 | configure 56 | depcomp 57 | doxygen.conf 58 | install-sh 59 | libserial.pc 60 | libserial.spec 61 | libtool 62 | ltmain.sh 63 | missing 64 | stamp-h1 65 | 66 | # Examples 67 | examples/main_page_example 68 | examples/serial_port_read 69 | examples/serial_port_read_write 70 | examples/serial_port_write 71 | examples/serial_stream_read 72 | examples/serial_stream_read_write 73 | examples/serial_stream_write 74 | 75 | m4/libtool.m4 76 | m4/ltoptions.m4 77 | m4/ltsugar.m4 78 | m4/ltversion.m4 79 | m4/lt~obsolete.m4 80 | 81 | # Python files 82 | sip/Makefile.sip 83 | sip/configure.py 84 | sip/libserial.exp 85 | sip/libserial.sbf 86 | sip/libserial.so 87 | sip/sipAPIlibserial.h 88 | sip/siplibserialcmodule.cpp 89 | sip/siplibserialLibSerial.cpp 90 | sip/siplibserialLibSerialBaudRate.cpp 91 | sip/siplibserialLibSerialCharacterSize.cpp 92 | sip/siplibserialLibSerialFlowControl.cpp 93 | sip/siplibserialLibSerialParity.cpp 94 | sip/siplibserialLibSerialStopBits.cpp 95 | sip/siplibserialSerialPort.cpp 96 | sip/siplibserialSerialPortAlreadyOpen.cpp 97 | sip/siplibserialSerialPortNotOpen.cpp 98 | sip/siplibserialSerialPortOpenFailed.cpp 99 | sip/siplibserialSerialPortReadTimeout.cpp 100 | sip/siplibserialSerialPortUnsupportedBaudRate.cpp 101 | sip/siplibserialstd.cpp 102 | sip/siplibserialstdexception.cpp 103 | sip/siplibserialstdinvalid_argument.cpp 104 | sip/siplibserialstdios_base.cpp 105 | sip/siplibserialstdios_baseopenmode.cpp 106 | sip/siplibserialstdlogic_error.cpp 107 | sip/siplibserialstdruntime_error.cpp 108 | sip/siplibserialstdstring.cpp 109 | sip/siplibserialstdvector1300.cpp 110 | sip/siplibserialstdvector1800.cpp 111 | sip/siplibserialstdvector1900.cpp 112 | sip/siplibserialstdvector2400.cpp 113 | 114 | # Test files 115 | test/MakeFile 116 | test/MakeFile.in 117 | test/UnitTests 118 | test/unit_tests 119 | Testing/ 120 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | let g:ale_cpp_clang_options="-std=c++14 -Wall -Isrc -Weffc++" 2 | let g:ale_cpp_clangtidy_options=g:ale_cpp_clang_options 3 | let g:ale_cpp_clangtidy_checks=['*', '-fuchsia-default-arguments', '-google-runtime-int', '-llvm-header-guard'] 4 | let g:ale_cpp_gcc_options=g:ale_cpp_clang_options 5 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import ycm_core 3 | 4 | def FlagsForFile( filename, **kwargs ): 5 | flags = [ '-Wall', 6 | '-Wextra', 7 | '-Werror', 8 | '-std=c++14', 9 | '-x', 'c++', 10 | '-I', 11 | '.', 12 | '-I', 13 | 'src' 14 | ] 15 | 16 | return { 'flags': flags, 17 | 'do_cache': True } 18 | 19 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Manish P. Pagey 2 | Crayzee Wulf 3 | Jay Sachdev 4 | Jan Wedekind 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Minimum version is 3.5 (this supports Ubuntu 16.04 and later, for example) 3 | # 4 | CMAKE_MINIMUM_REQUIRED(VERSION 3.5) 5 | 6 | # 7 | # Project version numbering using semantic versioning. See: 8 | # https://semver.org/ 9 | # 10 | # These are used to set VERSION and SOVERSION properties of the LibSerial 11 | # libarary. See: 12 | # - https://cmake.org/cmake/help/latest/prop_tgt/SOVERSION.html 13 | # - https://cmake.org/cmake/help/latest/prop_tgt/VERSION.html 14 | # 15 | PROJECT(LibSerial LANGUAGES C CXX VERSION 1.0.0) 16 | 17 | option(LIBSERIAL_ENABLE_TESTING "Enables building unit tests" ON) 18 | option(LIBSERIAL_BUILD_EXAMPLES "Enables building example programs" ON) 19 | option(LIBSERIAL_PYTHON_ENABLE "Enables building the library with Python SIP bindings" ON) 20 | option(LIBSERIAL_BUILD_DOCS "Build the Doxygen docs" ON) 21 | 22 | # 23 | # Project specific options and variables 24 | # 25 | OPTION(INSTALL_STATIC "Install static library." ON) 26 | OPTION(INSTALL_SHARED "Install shared object library." ON) 27 | 28 | # 29 | # LibSerial requies a C++ compiler that supports at least C++14 standard 30 | # 31 | SET(CMAKE_CXX_STANDARD 14) 32 | SET(CMAKE_STANDARD_REQUIRES ON) 33 | 34 | INCLUDE(ExternalProject) 35 | 36 | if (LIBSERIAL_ENABLE_TESTING) 37 | ENABLE_TESTING() 38 | endif() 39 | SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 40 | 41 | # 42 | # Create compile_commands.json file so that it may be used by various 43 | # editors/plugins/IDEs that support it. 44 | # 45 | SET(CMAKE_EXPORT_COMPILE_COMMANDS 1) 46 | 47 | # 48 | # Use GNU standard installation directories. CMake will use /usr/local 49 | # as the default install directory. Users may override this by setting 50 | # CMAKE_INSTALL_PREFIX. For example: 51 | # 52 | # cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. 53 | # 54 | INCLUDE(GNUInstallDirs) 55 | 56 | # 57 | # Prefer -pthread compiler and linker flag when using libpthread. This must 58 | # be set before call to FIND_PACKAGE(Threads). 59 | # 60 | SET(THREADS_HAVE_PTHREAD_ARG 1) 61 | if (LIBSERIAL_BUILD_DOCS) 62 | FIND_PACKAGE(Doxygen REQUIRED) 63 | endif() 64 | if (LIBSERIAL_ENABLE_TESTING) 65 | FIND_PACKAGE(Boost COMPONENTS unit_test_framework REQUIRED) 66 | endif() 67 | if (LIBSERIAL_PYTHON_ENABLE) 68 | FIND_PACKAGE(PythonLibs REQUIRED) 69 | endif() 70 | #FIND_PACKAGE(SIP REQUIRED) 71 | FIND_PACKAGE(Threads REQUIRED) 72 | 73 | # 74 | # Use -DCMAKE_BUILD_TYPE=Release or -DCMAKE_BUILD_TYPE=Debug to let CMake 75 | # decide whether to use debug or optimization flags. We should not hard-code 76 | # them here. Similarly, let CMake handle flags needed for shared object files 77 | # (such as -fPIC). Additionally, "-pthread" flag will also be handled by CMake 78 | # via the use of CMAKE_THREAD_LIBS_INIT (cmake < 3.1) or Threads::Threads. 79 | # 80 | ADD_DEFINITIONS( 81 | -Wall 82 | -Wcast-align 83 | -Wchar-subscripts 84 | -Wdouble-promotion 85 | -Wextra 86 | -Wfatal-errors 87 | -Wformat 88 | -Wformat-security 89 | -Wlogical-op 90 | -Wno-format-extra-args 91 | -Wno-long-long 92 | -Wno-parentheses 93 | -Wno-psabi 94 | -Wno-variadic-macros 95 | -Woverlength-strings 96 | -Wpacked 97 | -Wpointer-arith 98 | -Wunused-local-typedefs 99 | -Wwrite-strings 100 | 101 | -fstrict-aliasing 102 | -fno-check-new 103 | -fno-common 104 | -fvisibility=default 105 | -pedantic 106 | ) 107 | 108 | if (LIBSERIAL_ENABLE_TESTING) 109 | SET(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gtest") 110 | 111 | EXTERNALPROJECT_ADD(GTestExternal 112 | PREFIX "${GTEST_PREFIX}" 113 | URL https://github.com/google/googletest/archive/refs/tags/v1.16.0.tar.gz 114 | URL_HASH SHA1=517f27ed21b40f9927ab91f2abc147519cedb5a5 115 | INSTALL_COMMAND "" 116 | ) 117 | 118 | SET(LIBPREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}") 119 | SET(LIBSUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}") 120 | 121 | SET(GTEST_LOCATION "${GTEST_PREFIX}/src/GTestExternal-build/lib") 122 | SET(GTEST_LIBRARY "${GTEST_LOCATION}/${LIBPREFIX}gtest${LIBSUFFIX}") 123 | SET(GTEST_MAINLIB "${GTEST_LOCATION}/${LIBPREFIX}gtest_main${LIBSUFFIX}") 124 | 125 | ADD_LIBRARY(GTest IMPORTED STATIC GLOBAL) 126 | SET_TARGET_PROPERTIES(GTest 127 | PROPERTIES 128 | IMPORTED_LOCATION "${GTEST_LIBRARY}" 129 | IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}" 130 | ) 131 | 132 | ADD_LIBRARY(GTestMain IMPORTED STATIC GLOBAL) 133 | SET_TARGET_PROPERTIES(GTestMain 134 | PROPERTIES 135 | IMPORTED_LOCATION "${GTEST_MAINLIB}" 136 | IMPORTED_LINK_INTERFACE_LIBRARIES "${GTEST_LIBRARY};${CMAKE_THREAD_LIBS_INIT}" 137 | ) 138 | 139 | ADD_DEPENDENCIES(GTest GTestExternal) 140 | ADD_DEPENDENCIES(GTestMain GTestExternal) 141 | 142 | EXTERNALPROJECT_GET_PROPERTY(GTestExternal source_dir) 143 | 144 | INCLUDE_DIRECTORIES( 145 | BEFORE ${GTEST_PREFIX}/src/GTestExternal/googletest/include 146 | ${Boost_INCLUDE_DIRS} 147 | ) 148 | endif() 149 | 150 | SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 151 | SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 152 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 153 | SET(CMAKE_INSTALL_MESSAGE ALWAYS) 154 | 155 | if (LIBSERIAL_BUILD_EXAMPLES) 156 | ADD_SUBDIRECTORY(examples) 157 | endif() 158 | if (LIBSERIAL_PYTHON_ENABLE) 159 | ADD_SUBDIRECTORY(sip) 160 | endif() 161 | ADD_SUBDIRECTORY(src) 162 | if (LIBSERIAL_ENABLE_TESTING) 163 | ADD_SUBDIRECTORY(test) 164 | endif() 165 | 166 | # 167 | # Create pkg-config file for cmake builds as well as autotool builds 168 | # 169 | set(prefix ${CMAKE_INSTALL_PREFIX}) 170 | set(exec_prefix ${CMAKE_INSTALL_PREFIX}) 171 | set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) 172 | set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) 173 | set(VERSION ${PROJECT_VERSION}) 174 | configure_file(libserial.pc.in libserial.pc @ONLY) 175 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libserial.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 176 | 177 | if (LIBSERIAL_BUILD_DOCS) 178 | CONFIGURE_FILE( 179 | ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.conf.in 180 | ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf.in @ONLY 181 | ) 182 | 183 | ADD_CUSTOM_TARGET(docs ALL 184 | ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.conf.in 185 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 186 | COMMENT "Generating API documentation with Doxygen" VERBATIM 187 | ) 188 | endif() 189 | 190 | # 191 | # Packaging support 192 | # 193 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 194 | add_subdirectory(packaging) 195 | endif() 196 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2005-09-19 2 | 3 | * configure.in: Released version 0.5.0. 4 | 5 | * src/PosixSignalDispatcher.cpp (Repository): Formatting changes 6 | only. No logical changes. 7 | 8 | * src/PosixSignalDispatcher.h (Repository): Formatting changes 9 | only. No logical changes. 10 | 11 | * src/SerialPort.cpp (Repository): Formatting changes only. No 12 | logical changes. 13 | 14 | 2005-09-18 15 | 16 | * src/SerialPort.h (class SerialPort): The constructor for the 17 | class is now "explicit" to make sure that a std::string does not 18 | get converted to a SerialPort object through implicit 19 | conversion. The destructor is not virtual anymore as this class is 20 | not designed to be polymorphic. 21 | 22 | 2005-09-06 Jan Wedekind 23 | 24 | * examples/write_port.cpp: An example for writing commands to 25 | the serial port was added. 26 | * src/SerialStream.h: Functions for adjusting the port's VTIME- 27 | and VMIN-parameter where added. 28 | * src/SerialStreamBuf.cc: Missing return statement was added. 29 | 30 | 2003-12-30 Manish P. Pagey 31 | 32 | * src/SerialStreamBuf.cc: Interchanged "case 1" and "case 2" in 33 | SerialStreamBuf::SetNumOfStopBits() to make sure that stop bits 34 | are set correctly. This bug was pointed out by Olivier Chambard. 35 | 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, LibSerial Development Team 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /LibSerial.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "." 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src examples docs 2 | 3 | if PYTHON 4 | SUBDIRS += sip 5 | endif 6 | 7 | if TESTS 8 | SUBDIRS += test 9 | endif 10 | 11 | ACLOCAL_AMFLAGS = -I m4 12 | 13 | EXTRA_DIST = doxygen.conf.in Makefile.dist libserial.spec libserial.pc 14 | 15 | docs: 16 | make dox 17 | 18 | dox: 19 | doxygen doxygen.conf 20 | 21 | pkgconfigdir = $(libdir)/pkgconfig 22 | pkgconfig_DATA = libserial.pc 23 | -------------------------------------------------------------------------------- /Makefile.dist: -------------------------------------------------------------------------------- 1 | all: 2 | mkdir -pv m4 3 | autoreconf -i --force --verbose 4 | 5 | configure: 6 | ./configure 7 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crayzeewulf/libserial/a471ae8dee54e8770e4d47e60fba4acf29d8e7ad/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crayzeewulf/libserial/a471ae8dee54e8770e4d47e60fba4acf29d8e7ad/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Libserial 2 | 3 | Thanks for checking out LibSerial! LibSerial provides a convenient, object oriented approach to accessing serial ports on Linux operating system. 4 | 5 | After you get to know LibSerial a bit, if you find that you have ideas for improvement, please be sure to let us know! 6 | 7 | If you simply want to use LibSerial and you already utilize a Debian Linux distribution, use apt to install the current release package: 8 | 9 | ```sh 10 | sudo apt install libserial-dev 11 | ``` 12 | 13 | > 14 | > Note that the above command may install an older version of LibSerial (e.g. 0.6.0 on Ubuntu 18.04). 15 | > In order to use the latest features and the example project mentioned below, please build the 16 | > library from source code as described in 17 | > [here](https://github.com/crayzeewulf/libserial#developers). We are working to 18 | > release updated versions of the library from package repositories of major Linux distribution 19 | > in the mean time and apologize for the inconvenience. 20 | > 21 | 22 | Example code to demonstrate how to use the library can be found in the [`examples`](https://github.com/crayzeewulf/libserial/tree/master/examples) directory. 23 | A self-contained example project demonstrating the use of CMake and GNU Autotools (make) can be found in [`examples/example_project`](https://github.com/crayzeewulf/libserial/tree/master/examples/example_project) directory. 24 | 25 | ## Developers 26 | 27 | If you are a developer and would like to make use of the latest code, you will 28 | need to have a few packages installed to build LibSerial: a recent g++ release 29 | (anything after gcc-3.2 should work), autotools, cmake, doxygen, sphinx, the 30 | python3 sip library, the boost unit test library, pkg-config, and Google Test 31 | (gtest). The following commands should install the required packages for 32 | Debian/Ubuntu users: 33 | 34 | ```sh 35 | sudo apt update 36 | sudo apt install g++ git autogen autoconf build-essential cmake graphviz \ 37 | libboost-dev libboost-test-dev libgtest-dev libtool \ 38 | python3-sip-dev doxygen python3-sphinx pkg-config \ 39 | python3-sphinx-rtd-theme 40 | ``` 41 | 42 | 43 | If you get the source code from github and would like to install the library, there are a few steps you will need to accomplish: 44 | 45 | ### Building Using CMake 46 | 47 | If you are using CMake, to build the library you can simply run the `compile.sh` script: 48 | 49 | ```sh 50 | ./compile.sh 51 | ``` 52 | 53 | To install the library: 54 | 55 | ```sh 56 | cd build 57 | sudo make install 58 | ``` 59 | 60 | You can specify an installation directory different from the default, (/usr/local/), by replacing the `cmake ..` command in the `compile.sh` script. For example, to install under `/usr` instead of the `/usr/local` directory, use the following: 61 | 62 | ```sh 63 | cmake -DCMAKE_INSTALL_PREFIX=/usr .. 64 | ``` 65 | 66 | ### Building Using GNU Autotools 67 | 68 | GNU Autotools is currently configured to built all unit tests, so first you will need to compile the GTest library object files and copy `libgtest.a` and `libgtest_main.a` into your `/usr/lib/` directory which you can accomplish by running the `gtest.sh` convenience script: 69 | 70 | ```sh 71 | ./gtest.sh 72 | ``` 73 | 74 | To generate the configure script: 75 | 76 | ```sh 77 | make -f Makefile.dist 78 | ``` 79 | 80 | To execute the `configure` script, first create a build directory, then run the script from the build directory as follows: 81 | 82 | ```sh 83 | ../configure 84 | ``` 85 | 86 | You can specify an installation directory different from the default, (`/usr/local/`), by adding `--prefix=/installation/directory/path/` to the configure command. For example, to install into the top level include directory as the package manager would accomplish, you can simply run the following: 87 | 88 | ```sh 89 | ./configure --prefix=/usr/ 90 | ``` 91 | 92 | Once you have executed the `configure` script, you can build the library with `make` and install with `make install`: 93 | 94 | ```sh 95 | make 96 | sudo make install 97 | ``` 98 | 99 | ## Example Code and Unit Tests 100 | 101 | If you are interested in running the unit tests or example code, ensure serial port names are appropriate for your hardware configuration in the `examples/` directory files and in the `test/UnitTests.h` file as such: 102 | 103 | ```cpp 104 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 105 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 106 | ``` 107 | 108 | Example code and Unit test executables are easily built using the cmake compile script and can be run from the `build` directory: 109 | 110 | ```sh 111 | ./compile 112 | ``` 113 | 114 | ```sh 115 | ./build/bin/UnitTests 116 | ``` 117 | 118 | ```sh 119 | ./build/bin/SerialPortReadWriteExample 120 | ``` 121 | 122 | Unit test executables built using make can be run from the `build` directory in the following manner: 123 | 124 | ```sh 125 | ctest -V . 126 | ``` 127 | 128 | ## Hardware and Software Considerations 129 | 130 | If needed, you can grant user permissions to utilize the hardware ports in the following manner, (afterwards a reboot is required): 131 | 132 | ```sh 133 | sudo usermod -a -G dialout $USER 134 | sudo usermod -a -G plugdev $USER 135 | ``` 136 | 137 | ## Socat 138 | 139 | Socat is a useful tool to allow hardware ports to communicate on the same system via a software pipe. As an example, to allow hardware UART port `/dev/ttyS0` to communicate via software with hardware UART port `/dev/ttyS1`: 140 | 141 | ```sh 142 | socat -d -d pty,raw,echo=0,link=/dev/ttyS0 pty,raw,echo=0,link=/dev/ttyS1 143 | ``` 144 | 145 | ## Documentation 146 | 147 | Complete documentation is available [here](http://libserial.readthedocs.io/en/latest/index.html). 148 | 149 | 150 | > Let us know that this repository was useful to you by clicking the "star" in 151 | > the upper right corner of the LibSerial Github home page! 152 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -x 4 | mkdir -p build 5 | cd build 6 | cmake .. 7 | #cmake -DCMAKE_INSTALL_PREFIX=/usr .. 8 | make 9 | cd .. 10 | make -j3 -C build 11 | sphinx-build -b html docs/user_manual/ docs/html/ 12 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Indicate the package name and the version to automake 2 | AC_INIT([libserial], [1.0.0]) 3 | 4 | dnl Indicate the configuration revision number 5 | AC_REVISION($Revision: 1.15 $) 6 | 7 | dnl Input and Output configuration information 8 | 9 | AC_CONFIG_SRCDIR([src/SerialStream.cpp]) 10 | AM_CONFIG_HEADER(config.h) 11 | AC_CONFIG_MACRO_DIR([m4]) 12 | AM_INIT_AUTOMAKE 13 | AM_MAINTAINER_MODE 14 | 15 | dnl Checks for programs. 16 | AC_PROG_AWK 17 | AC_PROG_CC 18 | AC_PROG_CXX 19 | AC_PROG_INSTALL 20 | AC_PROG_LIBTOOL 21 | AC_PROG_LN_S 22 | AC_PROG_MAKE_SET 23 | 24 | dnl LibSerial now requires at least C++14 features in the compiler. 25 | AX_CXX_COMPILE_STDCXX(14, noext, mandatory) 26 | 27 | AC_CHECK_PROG(DOCBOOK2PDF, docbook2pdf, docbook2pdf, no) 28 | 29 | if test "x$DOCBOOK2PDF" == "xno"; then 30 | AC_MSG_WARN([Could not find docbook2pdf. Disabling creation of user manual.]) 31 | HAVE_DOCBOOK2PDF="no" 32 | else 33 | HAVE_DOCBOOK2PDF="yes" 34 | fi 35 | 36 | AC_SUBST(DOCBOOK2PDF) 37 | AM_CONDITIONAL(HAVE_DOCBOOK2PDF, test x$HAVE_DOCBOOK2PDF = xyes) 38 | 39 | dnl Checks for header files. 40 | AC_CHECK_HEADERS(fcntl.h unistd.h) 41 | 42 | dnl Checks for typedefs, structures, and compiler characteristics. 43 | AC_C_CONST 44 | AC_C_INLINE 45 | 46 | AC_ARG_WITH([python3], 47 | AS_HELP_STRING([--without-python3], [Disable Python bindings]), 48 | [], [with_python3=yes]) 49 | AM_CONDITIONAL([PYTHON], [test "${with_python3}" != "no"]) 50 | 51 | AC_ARG_ENABLE([tests], 52 | AS_HELP_STRING([--disable-tests], [Disable tests]), 53 | [], [enable_tests=yes]) 54 | AM_CONDITIONAL([TESTS], [test "${enable_tests}" != "no"]) 55 | 56 | AC_OUTPUT([Makefile 57 | doxygen.conf 58 | libserial.spec 59 | docs/UML/Makefile 60 | docs/Makefile 61 | examples/Makefile 62 | sip/configure.py 63 | sip/Makefile 64 | src/Makefile 65 | src/libserial/Makefile 66 | test/Makefile 67 | libserial.pc]) 68 | -------------------------------------------------------------------------------- /dockerfiles/centos/7/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Run the following command from top-level folder of libserial source code 3 | # to build the libserial image for CentOS-7: 4 | # 5 | # docker build -t libserial:centos-7 -f dockerfiles/centos/7/Dockerfile . 6 | # 7 | # ------------------------------------------------------------------------------ 8 | # base 9 | # ------------------------------------------------------------------------------ 10 | FROM centos:7 AS base 11 | 12 | RUN yum install -y centos-release-scl \ 13 | && yum install -y devtoolset-7-gcc-c++ \ 14 | && yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ 15 | && yum install -y \ 16 | boost-devel \ 17 | cmake3 \ 18 | doxygen \ 19 | graphviz \ 20 | make \ 21 | rpm-build \ 22 | python-devel 23 | 24 | # ------------------------------------------------------------------------------ 25 | # build 26 | # ------------------------------------------------------------------------------ 27 | FROM base AS build 28 | 29 | ENV CC /opt/rh/devtoolset-7/root/bin/gcc 30 | ENV CXX /opt/rh/devtoolset-7/root/bin/g++ 31 | COPY . /usr/src/libserial 32 | RUN cd /usr/src/libserial \ 33 | && rm -rf build \ 34 | && mkdir -p build \ 35 | && cd build \ 36 | && cmake3 -DCMAKE_INSTALL_PREFIX=/usr .. \ 37 | && make -j$(nproc) \ 38 | && make install \ 39 | && cpack3 -G RPM 40 | 41 | # ------------------------------------------------------------------------------ 42 | # release 43 | # ------------------------------------------------------------------------------ 44 | FROM centos:7 AS release 45 | COPY --from=build /usr/src/libserial/build/libserial*.rpm /usr/src/ 46 | RUN rpm -ivh /usr/src/libserial*.rpm 47 | -------------------------------------------------------------------------------- /dockerfiles/debian/buster/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Run the following command from top-level folder of libserial source code 3 | # to build the libserial image for Debian-buster: 4 | # 5 | # docker build -t libserial:debian-buster -f dockerfiles/debian/buster/Dockerfile . 6 | # 7 | # ------------------------------------------------------------------------------ 8 | # base 9 | # ------------------------------------------------------------------------------ 10 | FROM debian:buster AS base 11 | 12 | ENV DEBIAN_FRONTEND=noninteractive 13 | RUN apt-get -yq update && apt-get install -yq --no-install-recommends \ 14 | build-essential \ 15 | cmake \ 16 | coreutils \ 17 | doxygen \ 18 | g++ \ 19 | graphviz \ 20 | libboost-test-dev \ 21 | libgtest-dev \ 22 | libpython-dev \ 23 | && apt-get autoremove -y \ 24 | && apt-get clean -y 25 | 26 | 27 | # ------------------------------------------------------------------------------ 28 | # build 29 | # ------------------------------------------------------------------------------ 30 | FROM base AS build 31 | 32 | COPY . /usr/src/libserial 33 | RUN cd /usr/src/libserial \ 34 | && rm -rf build \ 35 | && mkdir -p build \ 36 | && cd build \ 37 | && cmake -DCMAKE_INSTALL_PREFIX=/usr .. \ 38 | && make -j$(nproc) \ 39 | && make install \ 40 | && cpack -G DEB 41 | 42 | # ------------------------------------------------------------------------------ 43 | # release 44 | # ------------------------------------------------------------------------------ 45 | 46 | FROM debian:buster AS release 47 | COPY --from=build /usr/src/libserial/build/libserial*.deb /usr/src/ 48 | RUN dpkg -i /usr/src/libserial*.deb 49 | -------------------------------------------------------------------------------- /dockerfiles/ubuntu/16.04/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Run the following command from top-level folder of libserial source code 3 | # to build the libserial image for Ubuntu 16.04: 4 | # 5 | # docker build -t libserial:ubuntu-16.04 -f dockerfiles/ubuntu/16.04/Dockerfile . 6 | # 7 | # ------------------------------------------------------------------------------ 8 | # base 9 | # ------------------------------------------------------------------------------ 10 | FROM ubuntu:16.04 AS base 11 | 12 | ENV DEBIAN_FRONTEND=noninteractive 13 | RUN apt-get -yq update && apt-get install -yq --no-install-recommends \ 14 | build-essential \ 15 | cmake \ 16 | coreutils \ 17 | doxygen \ 18 | g++ \ 19 | graphviz \ 20 | libboost-test-dev \ 21 | libgtest-dev \ 22 | libpython-dev \ 23 | && apt-get autoremove -y \ 24 | && apt-get clean -y 25 | 26 | 27 | # ------------------------------------------------------------------------------ 28 | # build 29 | # ------------------------------------------------------------------------------ 30 | FROM base AS build 31 | 32 | COPY . /usr/src/libserial 33 | RUN cd /usr/src/libserial \ 34 | && rm -rf build \ 35 | && mkdir -p build \ 36 | && cd build \ 37 | && cmake -DCMAKE_INSTALL_PREFIX=/usr .. \ 38 | && make -j$(nproc) \ 39 | && make install \ 40 | && cpack -G DEB 41 | 42 | # ------------------------------------------------------------------------------ 43 | # release 44 | # ------------------------------------------------------------------------------ 45 | 46 | FROM ubuntu:16.04 AS release 47 | COPY --from=build /usr/src/libserial/build/libserial*.deb /usr/src/ 48 | RUN dpkg -i /usr/src/libserial*.deb 49 | -------------------------------------------------------------------------------- /dockerfiles/ubuntu/18.04/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Run the following command from top-level folder of libserial source code 3 | # to build the libserial image for Ubuntu 18.04: 4 | # 5 | # docker build -t libserial:ubuntu-18.04 -f dockerfiles/ubuntu/18.04/Dockerfile . 6 | # 7 | # ------------------------------------------------------------------------------ 8 | # base 9 | # ------------------------------------------------------------------------------ 10 | FROM ubuntu:18.04 AS base 11 | 12 | ENV DEBIAN_FRONTEND=noninteractive 13 | RUN apt-get -yq update && apt-get install -yq --no-install-recommends \ 14 | build-essential \ 15 | cmake \ 16 | coreutils \ 17 | doxygen \ 18 | g++ \ 19 | graphviz \ 20 | libboost-test-dev \ 21 | libgtest-dev \ 22 | libpython-dev \ 23 | && apt-get autoremove -y \ 24 | && apt-get clean -y 25 | 26 | 27 | # ------------------------------------------------------------------------------ 28 | # build 29 | # ------------------------------------------------------------------------------ 30 | FROM base AS build 31 | 32 | COPY . /usr/src/libserial 33 | RUN cd /usr/src/libserial \ 34 | && rm -rf build \ 35 | && mkdir -p build \ 36 | && cd build \ 37 | && cmake -DCMAKE_INSTALL_PREFIX=/usr .. \ 38 | && make -j$(nproc) \ 39 | && make install \ 40 | && cpack -G DEB 41 | 42 | # ------------------------------------------------------------------------------ 43 | # release 44 | # ------------------------------------------------------------------------------ 45 | 46 | FROM ubuntu:18.04 AS release 47 | COPY --from=build /usr/src/libserial/build/libserial*.deb /usr/src/ 48 | RUN dpkg -i /usr/src/libserial*.deb 49 | -------------------------------------------------------------------------------- /docs/.cvsignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | UserManual.pdf 4 | -------------------------------------------------------------------------------- /docs/MAINPAGE.md: -------------------------------------------------------------------------------- 1 | \mainpage 2 | Welcome to LibSerial 3 | === 4 | 5 | LibSerial provides a collection of C++ classes that allow object oriented 6 | access to serial ports on POSIX systems. 7 | 8 | The SerialPort class is available to simplified access to serial port 9 | settings along with a set of convenient read/write methods.
10 | This class is useful for embedded systems where a complete C++ STL 11 | may not be available. 12 | 13 | The SerialStream class allows access to serial ports in the same manner as 14 | standard C++ iostream objects. 15 | 16 | Member functions are provided in both classes for setting serial port 17 | parameters such as baud rate, character size, flow control, etc. 18 | 19 | LibSerial exists to simplify serial port programming on POSIX systems.
20 | Here is short example using libserial: 21 | 22 | \include main_page_example.cpp 23 | 24 | In addition to the C++ programming languge, LibSerial releases after version 25 | 0.6.0 also provide bindings to several scripting languages such as Python, 26 | Perl, PHP, Java, and Ruby. This provides developers a wide range languages to 27 | select when writing applications that need access to serial ports on POSIX 28 | compatible operating systems. LibSerial has received most extensive testing 29 | under Linux operating system. 30 | -------------------------------------------------------------------------------- /docs/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS=UML 2 | -------------------------------------------------------------------------------- /docs/UML/.cvsignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | 4 | -------------------------------------------------------------------------------- /docs/UML/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/UML/libserial_class_diagram.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crayzeewulf/libserial/a471ae8dee54e8770e4d47e60fba4acf29d8e7ad/docs/UML/libserial_class_diagram.dia -------------------------------------------------------------------------------- /docs/user_manual/Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LibSerial.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LibSerial.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/LibSerial" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/LibSerial" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/user_manual/api_documentation.rst: -------------------------------------------------------------------------------- 1 | API Documentation 2 | ================= 3 | 4 | The API documentation generated by doxygen is available `here 5 | `_. 6 | 7 | To generate a new set of docs using Sphinx, simply run: 8 | 9 | .. code-block:: bash 10 | 11 | sphinx-build -b html docs/user_manual/ docs/html/ 12 | 13 | The Sphinx output will be located in the */libserial/docs/html/* directory. 14 | 15 | To generate a new set of doxygen documentation, you can run the compile.sh script or simply invoke doxygen directly: 16 | 17 | .. code-block:: bash 18 | 19 | doxygen doxygen.conf.in 20 | 21 | The doxygen output will be located in the */libserial/build/docs/html/* directory. -------------------------------------------------------------------------------- /docs/user_manual/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # LibSerial documentation build configuration file, created by 4 | # sphinx-quickstart on Sun Sep 17 10:46:50 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # The suffix(es) of source filenames. 39 | # You can specify multiple suffix as a list of string: 40 | # 41 | source_suffix = ['.rst', '.md'] 42 | 43 | # The master toctree document. 44 | master_doc = 'index' 45 | 46 | # General information about the project. 47 | project = u'LibSerial' 48 | copyright = u'2004-2018, LibSerial Development Team' 49 | title = u'LibSerial Documentation' 50 | author = u'LibSerial Development Team' 51 | description = u'LibSerial provides a convenient, object oriented approach to accessing serial ports on POSIX systems.' 52 | category = u'Serial Communication' 53 | library_name = u'LibSerial' 54 | 55 | 56 | # The version info for the project you're documenting, acts as replacement for 57 | # |version| and |release|, also used in various other places throughout the 58 | # built documents. 59 | # 60 | # The short X.Y version. 61 | version = u'1.0' 62 | 63 | # The full version, including alpha/beta/rc tags. 64 | release = u'1.0.0' 65 | 66 | # The language for content autogenerated by Sphinx. Refer to documentation 67 | # for a list of supported languages. 68 | # 69 | # This is also used if you do content translation via gettext catalogs. 70 | # Usually you set "language" from the command line for these cases. 71 | language = 'en' 72 | 73 | # List of patterns, relative to source directory, that match files and 74 | # directories to ignore when looking for source files. 75 | # This patterns also effect to html_static_path and html_extra_path 76 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 77 | 78 | # The name of the Pygments (syntax highlighting) style to use. 79 | pygments_style = 'sphinx' 80 | 81 | # If true, `todo` and `todoList` produce output, else they produce nothing. 82 | todo_include_todos = False 83 | 84 | 85 | # -- Options for HTML output ---------------------------------------------- 86 | 87 | # The theme to use for HTML and HTML Help pages. See the documentation for 88 | # a list of builtin themes. 89 | # 90 | html_theme = 'sphinx_rtd_theme' 91 | 92 | # Theme options are theme-specific and customize the look and feel of a theme 93 | # further. For a list of options available for each theme, see the 94 | # documentation. 95 | # 96 | # html_theme_options = {} 97 | 98 | # Add any paths that contain custom static files (such as style sheets) here, 99 | # relative to this directory. They are copied after the builtin static files, 100 | # so a file named "default.css" will overwrite the builtin "default.css". 101 | #html_static_path = ['_static'] 102 | 103 | # -- Options for HTMLHelp output ------------------------------------------ 104 | 105 | # Output file base name for HTML help builder. 106 | htmlhelp_basename = 'LibSerialdoc' 107 | 108 | 109 | # -- Options for LaTeX output --------------------------------------------- 110 | 111 | latex_elements = { 112 | # The paper size ('letterpaper' or 'a4paper'). 113 | # 114 | # 'papersize': 'letterpaper', 115 | 116 | # The font size ('10pt', '11pt' or '12pt'). 117 | # 118 | # 'pointsize': '10pt', 119 | 120 | # Additional stuff for the LaTeX preamble. 121 | # 122 | # 'preamble': '', 123 | 124 | # Latex figure (float) alignment 125 | # 126 | # 'figure_align': 'htbp', 127 | } 128 | 129 | # Grouping the document tree into LaTeX files. List of tuples 130 | # (source start file, target name, title, 131 | # author, documentclass [howto, manual, or own class]). 132 | latex_documents = [ 133 | (master_doc, 'LibSerial.tex', title, 134 | author, 'manual'), 135 | ] 136 | 137 | 138 | # -- Options for manual page output --------------------------------------- 139 | 140 | # One entry per manual page. List of tuples 141 | # (source start file, name, description, authors, manual section). 142 | man_pages = [ 143 | (master_doc, library_name, title, author, 1) 144 | ] 145 | 146 | 147 | # -- Options for Texinfo output ------------------------------------------- 148 | 149 | # Grouping the document tree into Texinfo files. List of tuples 150 | # (source start file, target name, title, author, 151 | # dir menu entry, description, category) 152 | texinfo_documents = [ 153 | (master_doc, library_name, title, author, 154 | 'LibSerial', description, category), 155 | ] 156 | -------------------------------------------------------------------------------- /docs/user_manual/description.rst: -------------------------------------------------------------------------------- 1 | Description 2 | =========== 3 | 4 | LibSerial was created to simplify serial port programming on POSIX 5 | systems through a collection of object oriented C++ classes. 6 | 7 | The `SerialPort` class allows simplified access to serial port 8 | settings and usage through a convenient set of methods. 9 | This class is useful for embedded systems where a complete C++ STL 10 | may not be available. 11 | 12 | The `SerialStream` class allows access to serial ports in the same manner as 13 | standard C++ iostream objects. 14 | 15 | Methods are provided for setting serial port parameters 16 | such as baud rate, character size, flow control, etc. 17 | 18 | Here is short example using libserial: 19 | 20 | .. code-block:: c++ 21 | 22 | #include 23 | #include 24 | 25 | using namespace LibSerial; 26 | 27 | int main() 28 | { 29 | // Instantiate a Serial Port and a Serial Stream object. 30 | SerialPort serial_port; 31 | SerialStream serial_stream; 32 | 33 | // Open the hardware serial ports. 34 | serial_port.Open( "/dev/ttyUSB0" ); 35 | serial_stream.Open( "/dev/ttyUSB1" ); 36 | 37 | // Set the baud rates. 38 | serial_port.SetBaudRate( BaudRate::BAUD_115200 ); 39 | serial_stream.SetBaudRate( BaudRate::BAUD_115200 ); 40 | 41 | char write_byte_1 = 'a'; 42 | char write_byte_2 = 'b'; 43 | 44 | char read_byte_1 = 'A'; 45 | char read_byte_2 = 'B'; 46 | 47 | // Write a character. 48 | serial_port.Write(&write_byte_1, 1); 49 | serial_stream << write_byte_2; 50 | 51 | // Read a character. 52 | serial_port.Read(read_byte_1, 1); 53 | serial_stream >> read_byte_2; 54 | 55 | std::cout << "serial_port read: " << read_byte_1 << std::endl; 56 | std::cout << "serial_stream read: " << read_byte_2 << std::endl; 57 | 58 | // Close the Serial Port and Serial Stream. 59 | serial_port.Close(); 60 | serial_stream.Close(); 61 | } 62 | 63 | In addition to the C++ programming languge, LibSerial releases after version 64 | 0.6.0 also provide bindings to several scripting languages such as Python, 65 | Perl, PHP, Java, and Ruby. This provides developers a wide range languages to 66 | select when writing applications that need access to serial ports on POSIX 67 | compatible operating systems. LibSerial has received the most extensive testing 68 | on (Debian) Linux operating systems. 69 | -------------------------------------------------------------------------------- /docs/user_manual/design_documentation.rst: -------------------------------------------------------------------------------- 1 | Design Documentation 2 | ==================== 3 | 4 | LibSerial's Coding standards 5 | ---------------------------- 6 | 7 | Try to utilize these guidelines if you are contributing the LibSerial as a 8 | developer. Although we attempt to maintain these standards wherever practical, 9 | on occasion you might still discover a few deviations. 10 | 11 | Please familiarize yourselves with `C++ Core Guidelines 12 | `_ and try to 13 | follow these guidelines. 14 | 15 | LibSerial uses ISO standard C++ based on the C++14 standard. 16 | 17 | Use Doxygen style comments (with @ commands) for every: 18 | 19 | * Class 20 | * Data Member 21 | * Function 22 | 23 | * @brief command for every function 24 | * @param command (if not void) for every parameter 25 | * @return command (if not void) 26 | 27 | * File 28 | 29 | * @file command, (except @example files) 30 | * @copyright command 31 | 32 | Allman (BSD) indentation style 33 | 34 | 35 | Classes/Namespace/Structure/Enumeration names: CamelCase 36 | Class methods: CamelCase 37 | Class members: mCamelCase 38 | 39 | Arguments to methods/functions: camelCase (lower case first word) 40 | 41 | 42 | Naming Convention 43 | ----------------- 44 | Use CamelCase for Files, Classes, Namespace, Structures, Enumerations, Functions, Procedures, and Member Variables. 45 | 46 | Filenames are the name of the class or namespace within -- one class per file. 47 | 48 | Classes, Namespaces, Structures, Enumerations, and Functions start with a capitalized letter and are nouns: (e.g. SerialPort, SerialStream, etc.). 49 | Inhertied functions may be exceptions. 50 | 51 | Function names are a description of the return value, and Procedure names are a strong verb followed by an object. (See Code Complete 2 §7.6 for the difference between a function and a procedure verb.) 52 | 53 | Function arguments start with a lowercase letter and are nouns; (e.g. numberOfBytes, etc.) 54 | 55 | Member Variables start with a lowercase letter "m" and are nouns; (e.g. mFileDescriptor, etc.). 56 | 57 | Use underscores for non-member functions and local variables, lower case with an underscore to separate words; (e.g. lower_case, short_names). 58 | 59 | Constants and Globals are named identically to variables. 60 | 61 | Do not use abbreviations and be as precise and descriptive with naming as possible. 62 | 63 | Indentation 64 | ----------- 65 | 66 | Indentation shall be 4 space characters, not tabs. 67 | 68 | Braces shall begin and end on the indentation level. 69 | 70 | Namespaces are NOT indented. 71 | 72 | Case statements are NOT indented. 73 | 74 | Class visibility statements are NOT indented (public, protected, private). 75 | 76 | One statement per line -- this includes variable declarations. 77 | 78 | Do not put short if() ...; statements on one line. 79 | 80 | If the constructor initializers don't fit on a single line, put constructor initializer list items one per line, starting with the comma and aligned with the colon separator. For example: 81 | 82 | .. code-block:: c++ 83 | 84 | Class::Class() 85 | : var1(1) 86 | , var2(2) 87 | , var3(3) 88 | { 89 | ... 90 | } 91 | 92 | The purpose of this indentation policy, which can feel "incorrect" at times is to ensure that changes are isolated to the minimum number of lines. Our tools, (compilers, editors, diff viewers, and source code repository), all operate on a line-by-line basis. When someone makes a change that affects a portion anywhere in the line, the tools consider the entire line changed. This can lead to nasty issues like complex merge conflicts, or, worse, obscure the developer activity. 93 | 94 | Include Headers 95 | --------------- 96 | A good practice is to include headers in the order most local to least local and alphabetize your lists to avoid duplications. The purpose for this is to ensure that a proper dependency chain is maintained. As the project grows larger, these compilation failures sometimes can be difficult to identify and resolve. 97 | 98 | This means that header files have includes alphabetized in the order: 99 | 100 | * project includes 101 | * project dependency includes 102 | * system includes 103 | 104 | Source files have the includes in the order: 105 | 106 | * definition includes 107 | * project includes 108 | * project dependency includes 109 | * system includes 110 | -------------------------------------------------------------------------------- /docs/user_manual/download.rst: -------------------------------------------------------------------------------- 1 | Download 2 | ======== 3 | 4 | The latest version of LibSerial is 1.0.0. You can find the source code 5 | for LibSerial-1.0.0 `here `_. 6 | Older versions of LibSerial may also be found at the above site. 7 | -------------------------------------------------------------------------------- /docs/user_manual/feature_summary.rst: -------------------------------------------------------------------------------- 1 | Feature Summary 2 | =============== 3 | 4 | * Simplified serial port programming in C++ under POSIX operating systems. 5 | * Support for USB-serial converters. 6 | * Access serial ports from scripting languages such as PHP, Python, Perl, 7 | Ruby, and Java. 8 | -------------------------------------------------------------------------------- /docs/user_manual/index.rst: -------------------------------------------------------------------------------- 1 | .. LibSerial documentation master file, created by 2 | sphinx-quickstart on Sun Sep 17 10:46:50 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to LibSerial's documentation! 7 | ===================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :caption: Contents: 14 | 15 | feature_summary 16 | description 17 | download 18 | install 19 | tutorial 20 | api_documentation 21 | design_documentation 22 | links 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | -------------------------------------------------------------------------------- /docs/user_manual/install.rst: -------------------------------------------------------------------------------- 1 | Install 2 | ======= 3 | 4 | To install LibSerial the current release package on many Linux distributions you may simply use the package manager associated with your distribution: 5 | 6 | For Debian distrbutions: 7 | 8 | .. code-block:: bash 9 | 10 | sudo apt install libserial-dev 11 | 12 | For Arch Linux distributions: 13 | 14 | .. code-block:: bash 15 | 16 | sudo pacman -S libserial-dev 17 | 18 | To install LibSerial from source, first clone the repository at https://github.com/crayzeewulf/libserial 19 | 20 | Using https: 21 | 22 | .. code-block:: bash 23 | 24 | git clone https://github.com/crayzeewulf/libserial.git 25 | 26 | Using ssh: 27 | 28 | .. code-block:: bash 29 | 30 | git clone git@github.com:crayzeewulf/libserial.git 31 | 32 | Next, using make, execute the following commands from your libserial directory: 33 | 34 | .. code-block:: bash 35 | 36 | make -F Makefile.dist 37 | ./configure 38 | make 39 | 40 | To install the build to your /usr/local/ directory your may simply: 41 | 42 | .. code-block:: bash 43 | 44 | sudo make install 45 | 46 | To install to another directory, simply use the *prefix* argument in the configure step above: 47 | 48 | .. code-block:: bash 49 | 50 | ./configure --prefix= 51 | 52 | The code is also easily built using `CMake` via a bash script: 53 | 54 | .. code-block:: bash 55 | 56 | ./compile.sh 57 | 58 | To install, change directories to the build directory and proceed as with make: 59 | 60 | .. code-block:: bash 61 | 62 | cd build/ 63 | sudo make install -------------------------------------------------------------------------------- /docs/user_manual/links.rst: -------------------------------------------------------------------------------- 1 | Links 2 | ===== 3 | 4 | `LibSerial-1.0.0rc1 5 | `_ 6 | 7 | `Documentation 8 | `_ 9 | -------------------------------------------------------------------------------- /docs/user_manual/tutorial.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | Opening a Serial Port I/O Stream 5 | -------------------------------- 6 | 7 | A serial port instance, SerialPort, or an I/O stream instance, 8 | SerialStream, can be created and opened by providing the name of the 9 | serial port device to the constructor: 10 | 11 | .. code-block:: c++ 12 | 13 | #include 14 | #include 15 | 16 | using namespace LibSerial ; 17 | 18 | // Create and open the serial port for communication. 19 | SerialPort my_serial_port( "/dev/ttyS0" ); 20 | SerialStream my_serial_stream( "/dev/ttyUSB0" ) ; 21 | 22 | In certain applications, the name of the serial port device may not be known 23 | when the SerialStream instance is created. In such cases, the same effect as 24 | above can be achieved as follows: 25 | 26 | .. code-block:: c++ 27 | 28 | // Create a object instance. 29 | SerialPort my_serial_port; 30 | SerialStream my_serial_stream; 31 | 32 | // Obtain the serial port name from user input. 33 | std::cout << "Please enter the name of the serial device, (e.g. /dev/ttyUSB0): " << std::flush; 34 | std::string serial_port_name; 35 | std::cin >> serial_port_name; 36 | 37 | // Open the serial port for communication. 38 | my_serial_port.Open( serial_port_name ); 39 | my_serial_stream.Open( serial_port_name ); 40 | 41 | Setting the Baud Rate 42 | --------------------- 43 | 44 | The baud rate for the SerialStream can be set using the 45 | SerialStream::SetBaudRate() member function. 46 | 47 | .. code-block:: c++ 48 | 49 | // Set the desired baud rate using a SetBaudRate() method call. 50 | // Available baud rate values are defined in SerialStreamConstants.h. 51 | 52 | my_serial_port.SetBaudRate( BAUD_115200 ); 53 | my_serial_stream.SetBaudRate( BAUD_115200 ); 54 | 55 | Setting the Character Size 56 | -------------------------- 57 | 58 | .. code-block:: c++ 59 | 60 | // Set the desired character size using a SetCharacterSize() method call. 61 | // Available character size values are defined in SerialStreamConstants.h. 62 | my_serial_port.SetCharacterSize( CHAR_SIZE_8 ); 63 | my_serial_stream.SetCharacterSize( CHAR_SIZE_8 ); 64 | 65 | Setting the Flow-Control Type 66 | ----------------------------- 67 | 68 | .. code-block:: c++ 69 | 70 | // Set the desired flow control type using a SetFlowControl() method call. 71 | // Available flow control types are defined in SerialStreamConstants.h. 72 | my_serial_port.SetFlowControl( FLOW_CONTROL_HARD ); 73 | my_serial_stream.SetFlowControl( FLOW_CONTROL_HARD ); 74 | 75 | 76 | Setting the Parity Type 77 | ----------------------- 78 | 79 | .. code-block:: c++ 80 | 81 | // Set the desired parity type using a SetParity() method call. 82 | // Available parity types are defined in SerialStreamConstants.h. 83 | my_serial_port.SetParity( PARITY_ODD ); 84 | my_serial_stream.SetParity( PARITY_ODD ); 85 | 86 | 87 | Setting the Number of Stop Bits 88 | ------------------------------- 89 | 90 | .. code-block:: c++ 91 | 92 | // Set the number of stop bits using a SetNumOfStopBits() method call. 93 | // Available stop bit values are defined in SerialStreamConstants.h. 94 | my_serial_port.SetStopBits( STOP_BITS_1 ) ; 95 | my_serial_stream.SetStopBits( STOP_BITS_1 ) ; 96 | 97 | 98 | Reading Characters 99 | ------------------ 100 | 101 | Characters can be read from serial port instances using Read(), ReadByte(), 102 | and Readline() methods. For example: 103 | 104 | .. code-block:: c++ 105 | 106 | // Read one character from the serial port within the timeout allowed. 107 | int timeout_ms = 25; // timeout value in milliseconds 108 | char next_char; // variable to store the read result 109 | 110 | my_serial_port.ReadByte( next_char, timeout_ms ); 111 | my_serial_stream.read( next_char ); 112 | 113 | 114 | Characters can be read from serial streams using standard iostream operators. For example: 115 | 116 | .. code-block:: c++ 117 | 118 | // Read one character from the serial port. 119 | char next_char; 120 | my_serial_stream >> next_char; 121 | 122 | // You can also read other types of values from the serial port in a similar fashion. 123 | int data_size; 124 | my_serial_stream >> data_size; 125 | 126 | Other methods of standard C++ iostream objects could be used as well. 127 | For example, one can read characters from the serial stream using the get() method: 128 | 129 | .. code-block:: c++ 130 | 131 | // Read one byte from the serial port. 132 | char next_byte; 133 | my_serial_stream.get( next_byte ); 134 | 135 | Writing Characters 136 | ------------------ 137 | 138 | .. code-block:: c++ 139 | 140 | // Write a single character to the serial port. 141 | my_serial_port.WriteByte( 'U' ); 142 | my_serial_stream << 'U' ; 143 | 144 | // You can easily write strings. 145 | std::string my_string = "Hello, Serial Port." 146 | 147 | my_serial_port.Write( my_string ); 148 | my_serial_stream << my_string << std::endl ; 149 | 150 | // And, with serial stream objects, you can easily write any type 151 | // of object that is supported by a "<<" operator. 152 | double radius = 2.0 ; 153 | double area = M_PI * 2.0 * 2.0 ; 154 | 155 | my_serial_stream << area << std::endl ; 156 | 157 | Reading Blocks of Data 158 | ---------------------- 159 | 160 | .. code-block:: c++ 161 | 162 | // Read a whole array of data from the serial port. 163 | const int BUFFER_SIZE = 256; 164 | char input_buffer[BUFFER_SIZE]; 165 | 166 | my_serial_port.Read( input_buffer, BUFFER_SIZE ); 167 | my_serial_stream.read( input_buffer, BUFFER_SIZE ); 168 | 169 | Writing Blocks of Data 170 | ---------------------- 171 | 172 | .. code-block:: c++ 173 | 174 | // Write an array of data from the serial port. 175 | const int BUFFER_SIZE = 256; 176 | char output_buffer[BUFFER_SIZE]; 177 | 178 | for( int i=0; i 6 | #include 7 | 8 | #include 9 | 10 | int main() 11 | { 12 | using LibSerial::SerialPort ; 13 | using LibSerial::SerialStream ; 14 | 15 | // You can instantiate a Serial Port or a Serial Stream object, whichever you'd prefer to work with. 16 | // For this example, we will demonstrate by using both types of objects. 17 | SerialPort serial_port ; 18 | SerialStream serial_stream ; 19 | 20 | // Open hardware serial ports using the Open() method. 21 | serial_port.Open( "/dev/ttyUSB0" ) ; 22 | serial_stream.Open( "/dev/ttyUSB1" ) ; 23 | 24 | // Set the baud rates. 25 | using LibSerial::BaudRate ; 26 | serial_port.SetBaudRate( BaudRate::BAUD_115200 ) ; 27 | serial_stream.SetBaudRate( BaudRate::BAUD_115200 ) ; 28 | 29 | // Create a few variables with data we can send. 30 | char write_byte_1 = 'a' ; 31 | char write_byte_2 = 'b' ; 32 | 33 | char read_byte_1 = 'A' ; 34 | char read_byte_2 = 'B' ; 35 | 36 | // Read a byte to the serial port using SerialPort Write() methods. 37 | serial_port.WriteByte(write_byte_1) ; 38 | 39 | // With SerialStream objects you can read/write to the port using iostream operators. 40 | serial_stream << write_byte_2 ; 41 | 42 | // Specify a timeout value (in milliseconds). 43 | size_t timeout_milliseconds = 25 ; 44 | 45 | using LibSerial::ReadTimeout ; 46 | try 47 | { 48 | // Read a byte from the serial port using SerialPort Read() methods. 49 | serial_port.ReadByte(read_byte_1, timeout_milliseconds) ; 50 | 51 | // With SerialStream objects you can read/write to the port using iostream operators. 52 | serial_stream >> read_byte_2 ; 53 | } 54 | catch (const ReadTimeout&) 55 | { 56 | std::cerr << "The Read() call has timed out." << std::endl ; 57 | } 58 | 59 | std::cout << "serial_port read: " << read_byte_1 << std::endl ; 60 | std::cout << "serial_stream read: " << read_byte_2 << std::endl ; 61 | 62 | // Close the Serial Port and Serial Stream. 63 | serial_port.Close() ; 64 | serial_stream.Close() ; 65 | } 66 | -------------------------------------------------------------------------------- /examples/main_page_example.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example main_page_example.cpp 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 11 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 12 | 13 | int main() 14 | { 15 | using LibSerial::SerialPort ; 16 | using LibSerial::SerialStream ; 17 | 18 | // Instantiate a Serial Port and a Serial Stream object. 19 | SerialPort serial_port ; 20 | SerialStream serial_stream ; 21 | 22 | // Open the hardware serial ports. 23 | serial_port.Open( SERIAL_PORT_1 ) ; 24 | serial_stream.Open( SERIAL_PORT_2 ) ; 25 | 26 | // Set the baud rates. 27 | using LibSerial::BaudRate ; 28 | serial_port.SetBaudRate( BaudRate::BAUD_115200 ) ; 29 | serial_stream.SetBaudRate( BaudRate::BAUD_115200 ) ; 30 | 31 | char write_byte_1 = 'a' ; 32 | char write_byte_2 = 'b' ; 33 | 34 | char read_byte_1 = 'A' ; 35 | char read_byte_2 = 'B' ; 36 | 37 | // Write a character. 38 | serial_port.WriteByte(write_byte_1) ; 39 | serial_stream << write_byte_2 ; 40 | 41 | size_t timeout_milliseconds = 5 ; 42 | 43 | using LibSerial::ReadTimeout ; 44 | try 45 | { 46 | // Read a character. 47 | serial_port.ReadByte(read_byte_1, timeout_milliseconds) ; 48 | serial_stream >> read_byte_2 ; 49 | } 50 | catch (const ReadTimeout&) 51 | { 52 | std::cerr << "The Read() call has timed out." << std::endl ; 53 | } 54 | 55 | std::cout << "serial_port read: " << read_byte_1 << std::endl ; 56 | std::cout << "serial_stream read: " << read_byte_2 << std::endl ; 57 | 58 | // Close the Serial Port and Serial Stream. 59 | serial_port.Close() ; 60 | serial_stream.Close() ; 61 | } 62 | -------------------------------------------------------------------------------- /examples/serial_port_read.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example serial_port_read.cpp 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 13 | 14 | /** 15 | * @brief This example demonstrates configuring a serial port and 16 | * reading serial data. 17 | */ 18 | int main() 19 | { 20 | using namespace LibSerial ; 21 | 22 | // Instantiate a SerialPort object. 23 | SerialPort serial_port ; 24 | 25 | try 26 | { 27 | // Open the Serial Port at the desired hardware port. 28 | serial_port.Open(SERIAL_PORT_1) ; 29 | } 30 | catch (const OpenFailed&) 31 | { 32 | std::cerr << "The serial port did not open correctly." << std::endl ; 33 | return EXIT_FAILURE ; 34 | } 35 | 36 | // Set the baud rate of the serial port. 37 | serial_port.SetBaudRate(BaudRate::BAUD_115200) ; 38 | 39 | // Set the number of data bits. 40 | serial_port.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 41 | 42 | // Turn off hardware flow control. 43 | serial_port.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 44 | 45 | // Disable parity. 46 | serial_port.SetParity(Parity::PARITY_NONE) ; 47 | 48 | // Set the number of stop bits. 49 | serial_port.SetStopBits(StopBits::STOP_BITS_1) ; 50 | 51 | // Wait for data to be available at the serial port. 52 | while(!serial_port.IsDataAvailable()) 53 | { 54 | usleep(1000) ; 55 | } 56 | 57 | // Specify a timeout value (in milliseconds). 58 | size_t ms_timeout = 250 ; 59 | 60 | // Char variable to store data coming from the serial port. 61 | char data_byte ; 62 | 63 | // Read one byte from the serial port and print it to the terminal. 64 | try 65 | { 66 | // Read a single byte of data from the serial port. 67 | serial_port.ReadByte(data_byte, ms_timeout) ; 68 | 69 | // Show the user what is being read from the serial port. 70 | std::cout << data_byte << std::flush ; 71 | } 72 | catch (const ReadTimeout&) 73 | { 74 | std::cerr << "\nThe ReadByte() call has timed out." << std::endl ; 75 | } 76 | 77 | // Wait a brief period for more data to arrive. 78 | usleep(1000) ; 79 | 80 | DataBuffer read_buffer ; 81 | 82 | try 83 | { 84 | // Read as many bytes as are available during the timeout period. 85 | serial_port.Read(read_buffer, 0, ms_timeout) ; 86 | } 87 | catch (const ReadTimeout&) 88 | { 89 | for (size_t i = 0 ; i < read_buffer.size() ; i++) 90 | { 91 | std::cout << read_buffer.at(i) << std::flush ; 92 | } 93 | 94 | std::cerr << "The Read() call timed out waiting for additional data." << std::endl ; 95 | } 96 | 97 | // Successful program completion. 98 | std::cout << "The example program successfully completed!" << std::endl ; 99 | return EXIT_SUCCESS ; 100 | } 101 | -------------------------------------------------------------------------------- /examples/serial_port_read_write.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example serial_port_read_write.cpp 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 13 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 14 | 15 | /** 16 | * @brief This example demonstrates multiple methods to read and write 17 | * serial stream data. 18 | */ 19 | int main() 20 | { 21 | using namespace LibSerial ; 22 | 23 | // Instantiate two SerialPort objects. 24 | SerialPort serial_port_1 ; 25 | SerialPort serial_port_2 ; 26 | 27 | try 28 | { 29 | // Open the Serial Ports at the desired hardware devices. 30 | serial_port_1.Open(SERIAL_PORT_1) ; 31 | serial_port_2.Open(SERIAL_PORT_2) ; 32 | } 33 | catch (const OpenFailed&) 34 | { 35 | std::cerr << "The serial ports did not open correctly." << std::endl ; 36 | return EXIT_FAILURE ; 37 | } 38 | 39 | // Set the baud rates. 40 | serial_port_1.SetBaudRate(BaudRate::BAUD_115200) ; 41 | serial_port_2.SetBaudRate(BaudRate::BAUD_115200) ; 42 | 43 | // Set the number of data bits. 44 | serial_port_1.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 45 | serial_port_2.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 46 | 47 | // Set the hardware flow control. 48 | serial_port_1.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 49 | serial_port_2.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 50 | 51 | // Set the parity. 52 | serial_port_1.SetParity(Parity::PARITY_NONE) ; 53 | serial_port_2.SetParity(Parity::PARITY_NONE) ; 54 | 55 | // Set the number of stop bits. 56 | serial_port_1.SetStopBits(StopBits::STOP_BITS_1) ; 57 | serial_port_2.SetStopBits(StopBits::STOP_BITS_1) ; 58 | 59 | // Setup variables to store outgoing and incoming data. 60 | char write_byte_1 = 'a' ; 61 | char write_byte_2 = 'b' ; 62 | 63 | char read_byte_1 = ' ' ; 64 | char read_byte_2 = ' ' ; 65 | 66 | // Variables to store outgoing and incoming data. 67 | std::string write_string_1 = 68 | "\"Do what you can, with what you have, where you are.\" - Theodore Roosevelt" ; 69 | 70 | std::string write_string_2 = 71 | "\"Simplicity is prerequisite for reliability.\" - Edsger W. Dijkstra" ; 72 | 73 | std::string read_string_1 ; 74 | std::string read_string_2 ; 75 | 76 | // Print to the terminal what will take place next. 77 | std::cout << "\nUsing WriteByte() and ReadByte() for one byte of data:" 78 | << std::endl ; 79 | 80 | // Write a single byte of data to the serial ports. 81 | serial_port_1.WriteByte(write_byte_1) ; 82 | serial_port_2.WriteByte(write_byte_2) ; 83 | 84 | // Wait until the data has actually been transmitted. 85 | serial_port_1.DrainWriteBuffer() ; 86 | serial_port_2.DrainWriteBuffer() ; 87 | 88 | // Specify a timeout value (in milliseconds). 89 | size_t timeout_milliseconds = 25 ; 90 | 91 | try 92 | { 93 | // Read a single byte of data from the serial ports. 94 | serial_port_1.ReadByte(read_byte_1, timeout_milliseconds) ; 95 | serial_port_2.ReadByte(read_byte_2, timeout_milliseconds) ; 96 | } 97 | catch (const ReadTimeout&) 98 | { 99 | std::cerr << "The ReadByte() call has timed out." << std::endl ; 100 | } 101 | 102 | // Print to the terminal what was sent and what was received. 103 | std::cout << "\tSerial Port 1 sent:\t" << write_byte_1 << std::endl 104 | << "\tSerial Port 2 received:\t" << read_byte_2 << std::endl 105 | << std::endl ; 106 | 107 | std::cout << "\tSerial Port 2 sent:\t" << write_byte_2 << std::endl 108 | << "\tSerial Port 1 received:\t" << read_byte_1 << std::endl 109 | << std::endl ; 110 | 111 | // Print to the terminal what will take place next. 112 | std::cout << "Using Write() and Read() for a specified number of " 113 | << "bytes of data:" << std::endl ; 114 | 115 | // Write a string to each serial port. 116 | serial_port_1.Write(write_string_1) ; 117 | serial_port_2.Write(write_string_2) ; 118 | 119 | // Wait until the data has actually been transmitted. 120 | serial_port_1.DrainWriteBuffer() ; 121 | serial_port_2.DrainWriteBuffer() ; 122 | 123 | try 124 | { 125 | // Read the appropriate number of bytes from each serial port. 126 | serial_port_1.Read(read_string_1, write_string_2.size(), timeout_milliseconds) ; 127 | serial_port_2.Read(read_string_2, write_string_1.size(), timeout_milliseconds) ; 128 | } 129 | catch (const ReadTimeout&) 130 | { 131 | std::cerr << "The Read() call has timed out." << std::endl ; 132 | } 133 | 134 | // Print to the terminal what was sent and what was received. 135 | std::cout << "\tSerial Port 1 sent:\t" << write_string_1 << std::endl 136 | << "\tSerial Port 2 received:\t" << read_string_2 << std::endl 137 | << std::endl ; 138 | 139 | std::cout << "\tSerial Port 2 sent:\t" << write_string_2 << std::endl 140 | << "\tSerial Port 1 received:\t" << read_string_1 << std::endl 141 | << std::endl ; 142 | 143 | // Variable to hold user input. 144 | std::string user_input ; 145 | user_input.clear() ; 146 | 147 | // Print to the terminal what will take place next. 148 | std::cout << "Using Write() and ReadLine() to write a string and " 149 | << "read a line of data:" << std::endl << std::endl ; 150 | 151 | // Prompt the user for input. 152 | std::cout << R"(Enter something you would like to send over )" 153 | << R"(serial, (enter "Q" or "q" to quit): )" << std::flush ; 154 | 155 | while(true) 156 | { 157 | // Get input from the user. 158 | std::getline(std::cin, user_input) ; 159 | 160 | if (user_input == "q" || 161 | user_input == "Q" || 162 | user_input == "") 163 | { 164 | break ; 165 | } 166 | 167 | // Write the user input to the serial port. 168 | serial_port_1.Write(user_input + "\n") ; 169 | 170 | // Read the data transmitted from the corresponding serial port. 171 | serial_port_2.ReadLine(read_string_2) ; 172 | 173 | // Print to the terminal what was sent and what was received. 174 | std::cout << "\tSerial Port 1 sent:\t" << user_input << std::endl 175 | << "\tSerial Port 2 received:\t" << read_string_2 << std::endl ; 176 | } 177 | 178 | // Close the serial ports and end the program. 179 | serial_port_1.Close() ; 180 | serial_port_2.Close() ; 181 | 182 | // Successful program completion. 183 | std::cout << "The example program successfully completed!" << std::endl ; 184 | return EXIT_SUCCESS ; 185 | } 186 | -------------------------------------------------------------------------------- /examples/serial_port_write.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example serial_port_write.cpp 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 12 | 13 | /** 14 | * @brief This example reads the contents of a file and writes the entire 15 | * file to the serial port one character at a time. To use this 16 | * example, simply utilize TestFile.txt or another file of your 17 | * choosing as a command line argument. 18 | */ 19 | int main(int argc, char** argv) 20 | { 21 | using namespace LibSerial ; 22 | // Determine if an appropriate number of arguments has been provided. 23 | if (argc < 2) 24 | { 25 | // Error message to the user. 26 | std::cerr << "Usage: " << argv[0] << " " << std::endl ; 27 | 28 | // Exit the program if no input file argument has been given. 29 | return 1 ; 30 | } 31 | 32 | // Open the input file for reading. 33 | std::ifstream input_file(argv[1]) ; 34 | 35 | // Determine if the input file argument is valid to read data from. 36 | if (!input_file.good()) 37 | { 38 | std::cerr << "Error: Could not open file " 39 | << argv[1] << " for reading." << std::endl ; 40 | return 1 ; 41 | } 42 | 43 | // Instantiate a SerialPort object. 44 | SerialPort serial_port ; 45 | 46 | try 47 | { 48 | // Open the Serial Port at the desired hardware port. 49 | serial_port.Open(SERIAL_PORT_2) ; 50 | } 51 | catch (const OpenFailed&) 52 | { 53 | std::cerr << "The serial port did not open correctly." << std::endl ; 54 | return EXIT_FAILURE ; 55 | } 56 | 57 | // Set the baud rate of the serial port. 58 | serial_port.SetBaudRate(BaudRate::BAUD_115200) ; 59 | 60 | // Set the number of data bits. 61 | serial_port.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 62 | 63 | // Turn off hardware flow control. 64 | serial_port.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 65 | 66 | // Disable parity. 67 | serial_port.SetParity(Parity::PARITY_NONE) ; 68 | 69 | // Set the number of stop bits. 70 | serial_port.SetStopBits(StopBits::STOP_BITS_1) ; 71 | 72 | // Read characters from the input file and write them to the serial port. 73 | std::cout << "Writing input file contents to the serial port." << std::endl ; 74 | 75 | while (input_file) 76 | { 77 | // Create a variable to store data from the input file and write to the 78 | // serial port. 79 | char data_byte ; 80 | 81 | // Read data from the input file. 82 | input_file.read(&data_byte, 1) ; 83 | 84 | // Write the data to the serial port. 85 | serial_port.WriteByte(data_byte) ; 86 | 87 | // Wait until the data has actually been transmitted. 88 | serial_port.DrainWriteBuffer() ; 89 | 90 | // Print to the terminal what is being written to the serial port. 91 | std::cout << data_byte ; 92 | } 93 | 94 | // Successful program completion. 95 | std::cout << "The example program successfully completed!" << std::endl ; 96 | return EXIT_SUCCESS ; 97 | } 98 | -------------------------------------------------------------------------------- /examples/serial_stream_read.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example serial_stream_read.cpp 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 12 | 13 | /** 14 | * @brief This example demonstrates configuring a serial stream and 15 | * reading serial stream data. 16 | */ 17 | int main() 18 | { 19 | using namespace LibSerial ; 20 | 21 | // Instantiate a SerialStream object. 22 | SerialStream serial_stream ; 23 | 24 | try 25 | { 26 | // Open the Serial Port at the desired hardware port. 27 | serial_stream.Open(SERIAL_PORT_1) ; 28 | } 29 | catch (const OpenFailed&) 30 | { 31 | std::cerr << "The serial port did not open correctly." << std::endl ; 32 | return EXIT_FAILURE ; 33 | } 34 | 35 | // Set the baud rate of the serial port. 36 | serial_stream.SetBaudRate(BaudRate::BAUD_115200) ; 37 | 38 | // Set the number of data bits. 39 | serial_stream.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 40 | 41 | // Turn off hardware flow control. 42 | serial_stream.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 43 | 44 | // Disable parity. 45 | serial_stream.SetParity(Parity::PARITY_NONE) ; 46 | 47 | // Set the number of stop bits. 48 | serial_stream.SetStopBits(StopBits::STOP_BITS_1) ; 49 | 50 | // Wait for data to be available at the serial port. 51 | while(serial_stream.rdbuf()->in_avail() == 0) 52 | { 53 | usleep(1000) ; 54 | } 55 | 56 | // Keep reading data from serial port and print it to the screen. 57 | while(serial_stream.IsDataAvailable()) 58 | { 59 | // Variable to store data coming from the serial port. 60 | char data_byte ; 61 | 62 | // Read a single byte of data from the serial port. 63 | serial_stream.get(data_byte) ; 64 | 65 | // Show the user what is being read from the serial port. 66 | std::cout << data_byte ; 67 | 68 | // Wait a brief period for more data to arrive. 69 | usleep(1000) ; 70 | } 71 | 72 | // Successful program completion. 73 | std::cout << "Done." << std::endl ; 74 | return EXIT_SUCCESS ; 75 | } 76 | -------------------------------------------------------------------------------- /examples/serial_stream_read_write.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example serial_stream_read_write.cpp 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 14 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 15 | 16 | /** 17 | * @brief This example demonstrates multiple methods to read and write 18 | * serial stream data utilizing std::iostream functionality. 19 | */ 20 | int main() 21 | { 22 | using namespace LibSerial ; 23 | 24 | // Instantiate two SerialStream objects. 25 | SerialStream serial_stream_1 ; 26 | SerialStream serial_stream_2 ; 27 | 28 | try 29 | { 30 | // Open the Serial Ports at the desired hardware devices. 31 | serial_stream_1.Open(SERIAL_PORT_1) ; 32 | serial_stream_2.Open(SERIAL_PORT_2) ; 33 | } 34 | catch (const OpenFailed&) 35 | { 36 | std::cerr << "The serial ports did not open correctly." << std::endl ; 37 | return EXIT_FAILURE ; 38 | } 39 | 40 | // Set the baud rates. 41 | serial_stream_1.SetBaudRate(BaudRate::BAUD_115200) ; 42 | serial_stream_2.SetBaudRate(BaudRate::BAUD_115200) ; 43 | 44 | // Set the number of data bits. 45 | serial_stream_1.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 46 | serial_stream_2.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 47 | 48 | // Turn off hardware flow control. 49 | serial_stream_1.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 50 | serial_stream_2.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 51 | 52 | // Disable parity. 53 | serial_stream_1.SetParity(Parity::PARITY_NONE) ; 54 | serial_stream_2.SetParity(Parity::PARITY_NONE) ; 55 | 56 | // Set the number of stop bits. 57 | serial_stream_1.SetStopBits(StopBits::STOP_BITS_1) ; 58 | serial_stream_2.SetStopBits(StopBits::STOP_BITS_1) ; 59 | 60 | // Variables to store outgoing and incoming data. 61 | std::string write_string_1 = "\"Do what you can, with what you have, where you are.\" - Theodore Roosevelt" ; 62 | std::string write_string_2 = "\"Simplicity is prerequisite for reliability.\" - Edsger W. Dijkstra" ; 63 | 64 | std::string read_string_1 = "" ; 65 | std::string read_string_2 = "" ; 66 | 67 | // Print to the terminal what will take place next. 68 | std::cout << "\nUsing write() and read() for a specified number of " 69 | << "bytes of data:" << std::endl ; 70 | 71 | // Write a specified number of bytes of data. 72 | serial_stream_1.write(write_string_1.c_str(), write_string_1.size()) ; 73 | serial_stream_2.write(write_string_2.c_str(), write_string_2.size()) ; 74 | 75 | // Wait until the data has actually been transmitted. 76 | serial_stream_1.DrainWriteBuffer() ; 77 | serial_stream_2.DrainWriteBuffer() ; 78 | 79 | // Char arrays to store incoming data. 80 | char* read_array_1 = new char[write_string_2.size()] ; 81 | char* read_array_2 = new char[write_string_1.size()] ; 82 | 83 | // Use inheritted std::istream read() method to read the data. 84 | serial_stream_1.read(read_array_1, write_string_2.size()) ; 85 | serial_stream_2.read(read_array_2, write_string_1.size()) ; 86 | 87 | // Print to the terminal what was sent and what was received. 88 | std::cout << "\tSerial Port 1 sent:\t" << write_string_1 << std::endl 89 | << "\tSerial Port 2 received:\t" << read_array_2 << std::endl 90 | << std::endl ; 91 | 92 | std::cout << "\tSerial Port 2 sent:\t" << write_string_2 << std::endl 93 | << "\tSerial Port 1 received:\t" << read_array_1 << std::endl 94 | << std::endl ; 95 | 96 | // Print to the terminal what will take place next. 97 | std::cout << "Using the \"<<\" operator and getline() for a line of data:" 98 | << std::endl ; 99 | 100 | // Write a line at each serial port. 101 | serial_stream_1 << write_string_1 << std::endl ; 102 | serial_stream_2 << write_string_2 << std::endl ; 103 | 104 | // Wait until the data has actually been transmitted. 105 | serial_stream_1.DrainWriteBuffer() ; 106 | serial_stream_2.DrainWriteBuffer() ; 107 | 108 | // Read a line at each serial port. 109 | std::getline(serial_stream_1, read_string_1) ; 110 | std::getline(serial_stream_2, read_string_2) ; 111 | 112 | // Print to the terminal what was sent and what was received. 113 | std::cout << "\tSerial Port 1 sent:\t" << write_string_1 << std::endl 114 | << "\tSerial Port 2 received:\t" << read_string_2 << std::endl 115 | << std::endl ; 116 | 117 | std::cout << "\tSerial Port 2 sent:\t" << write_string_2 << std::endl 118 | << "\tSerial Port 1 received:\t" << read_string_1 << std::endl 119 | << std::endl ; 120 | 121 | // Variable to hold user input. 122 | std::string user_input ; 123 | user_input.clear() ; 124 | 125 | // Prompt the user for input. 126 | std::cout << "Type something you would like to send over serial," 127 | << " (enter \"Q\" or \"q\" to quit): " << std::flush ; 128 | 129 | while(true) 130 | { 131 | // Get input from the user. 132 | std::getline(std::cin, user_input) ; 133 | 134 | if (user_input == "q" || 135 | user_input == "Q" || 136 | user_input == "") 137 | { 138 | break ; 139 | } 140 | 141 | // Print to the terminal what will take place next. 142 | std::cout << "Using the \"<<\" and \">>\" operators to send " 143 | << "and receive your data: " << std::endl ; 144 | 145 | // Write the user input to the serial port. 146 | serial_stream_1 << user_input << std::endl ; 147 | 148 | // Read the data transmitted from the corresponding serial port. 149 | // Note: The ">>" operator behavior is tricky if whitespace or 150 | // nothing is entered by the user! 151 | serial_stream_2 >> read_string_2 ; 152 | 153 | // Print to the terminal what was sent and what was received. 154 | std::cout << "\tSerial Port 1 sent:\t" << user_input << std::endl 155 | << "\tSerial Port 2 received:\t" << read_string_2 << std::endl ; 156 | } 157 | 158 | // Close the serial ports and end the program. 159 | serial_stream_1.Close() ; 160 | serial_stream_2.Close() ; 161 | 162 | // Successful program completion. 163 | std::cout << "The example program successfully completed!" << std::endl ; 164 | return EXIT_SUCCESS ; 165 | } 166 | -------------------------------------------------------------------------------- /examples/serial_stream_write.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @example serial_stream_write.cpp 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 12 | 13 | 14 | /** 15 | * @brief This example reads the contents of a file and writes the entire 16 | * file to the serial port one character at a time. To use this 17 | * example, simply utilize TestFile.txt or another file of your 18 | * choosing as a command line argument. 19 | */ 20 | int main(int argc, char** argv) 21 | { 22 | using namespace LibSerial ; 23 | // Determine if an appropriate number of arguments has been provided. 24 | if (argc < 2) 25 | { 26 | // Error message to the user. 27 | std::cerr << "Usage: " << argv[0] << " " << std::endl ; 28 | 29 | // Exit the program if no input file argument has been given. 30 | return 1 ; 31 | } 32 | 33 | // Open the input file for reading. 34 | std::ifstream input_file(argv[1]) ; 35 | 36 | // Determine if the input file argument is valid to read data from. 37 | if (!input_file.good()) 38 | { 39 | std::cerr << "Error: Could not open file " 40 | << argv[1] << " for reading." << std::endl ; 41 | return 1 ; 42 | } 43 | 44 | // Instantiate a SerialStream object. 45 | SerialStream serial_stream ; 46 | 47 | try 48 | { 49 | // Open the Serial Port at the desired hardware port. 50 | serial_stream.Open(SERIAL_PORT_2) ; 51 | } 52 | catch (const OpenFailed&) 53 | { 54 | std::cerr << "The serial port did not open correctly." << std::endl ; 55 | return EXIT_FAILURE ; 56 | } 57 | 58 | // Set the baud rate of the serial port. 59 | serial_stream.SetBaudRate(BaudRate::BAUD_115200) ; 60 | 61 | // Set the number of data bits. 62 | serial_stream.SetCharacterSize(CharacterSize::CHAR_SIZE_8) ; 63 | 64 | // Turn off hardware flow control. 65 | serial_stream.SetFlowControl(FlowControl::FLOW_CONTROL_NONE) ; 66 | 67 | // Disable parity. 68 | serial_stream.SetParity(Parity::PARITY_NONE) ; 69 | 70 | // Set the number of stop bits. 71 | serial_stream.SetStopBits(StopBits::STOP_BITS_1) ; 72 | 73 | // Read characters from the input file and write them to the serial port. 74 | std::cout << "Writing input file contents to the serial port." << std::endl ; 75 | 76 | // Create a variable to store data from the input file and write to the serial port. 77 | char data_byte = 0 ; 78 | 79 | while (input_file) 80 | { 81 | // Read data from the input file. 82 | input_file.read(&data_byte, 1) ; 83 | 84 | // Write the data to the serial port. 85 | serial_stream.write(&data_byte, 1) ; 86 | 87 | // Wait until the data has actually been transmitted. 88 | serial_stream.DrainWriteBuffer() ; 89 | 90 | // Print to the terminal what is being written to the serial port. 91 | std::cout << data_byte ; 92 | } 93 | 94 | // Successful program completion. 95 | std::cout << "The example program successfully completed!" << std::endl ; 96 | return EXIT_SUCCESS ; 97 | } 98 | -------------------------------------------------------------------------------- /gtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | present_working_directory=$(pwd) 3 | cd /usr/src/gtest 4 | sudo cmake CMakeLists.txt 5 | sudo make 6 | sudo cp *.a /usr/lib 7 | cd $present_working_directory 8 | -------------------------------------------------------------------------------- /libserial.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libserial 7 | Description: C++ Serial port library 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lserial 10 | Cflags: -I${includedir} 11 | 12 | -------------------------------------------------------------------------------- /libserial.spec.in: -------------------------------------------------------------------------------- 1 | # If you want to build an executable that uses static libraries, 2 | # build your libraries in a separate root directory, and then run 3 | # the rpmbuild using "--define 'ink_static_root /your/static/rootdir'" 4 | 5 | # To avoid stripping the binaries, you can also: 6 | # "--define '__spec_install_post /usr/lib/rpm/brp-compress'" 7 | 8 | Name: libserial 9 | Summary: C++ library for programming serial ports on POSIX systems. 10 | Version: @VERSION@ 11 | # Use release "0" so that distro-released versions will override ours. 12 | Release: 0 13 | License: BSD 3-CLAUSE 14 | Group: Development/Libraries 15 | Source: %{name}-%{version}.tar.gz 16 | URL: http://libserial.sourceforge.net/ 17 | Prefix: %{_prefix} 18 | Packager: Automatic 19 | Vendor: GNU 20 | BuildRoot: %{_tmppath}/%{name}-%{version}-root 21 | 22 | # See debian/control for a full list of requirements. Maybe someone using an 23 | # rpm-based distribution would like to translate some or all of the Debian 24 | # package names given in debian/control to rpm equivalent packages. 25 | #Requires: gtk2 >= 2.4.0 26 | #BuildRequires: gtk2-devel >= 2.4.0 27 | 28 | %description 29 | A collection of C++ classes which allow the serial port on POSIX 30 | systems to be accessed like an iostream object. Special functions are 31 | provided for setting various parameters of the serial port such as the 32 | baud rate, character size, flow control and others. 33 | 34 | %prep 35 | %setup 36 | 37 | %build 38 | ### Needed for snapshot releases. 39 | MYCFLAGS="$RPM_OPT_FLAGS" 40 | 41 | if [ ! -x configure ]; then 42 | CFLAGS="$MYCFLAGS" ./autogen.sh $MYARCH_FLAGS --prefix=%{_prefix} --localstatedir=%{_localstatedir} --sysconfdir=%{_sysconfdir} 43 | else 44 | %configure 45 | fi 46 | make %{?_smp_mflags} 47 | 48 | %install 49 | rm -rf %{buildroot} 50 | %makeinstall 51 | 52 | %clean 53 | rm -rf %{buildroot} 54 | 55 | %files 56 | %defattr(-, root, root) 57 | %doc AUTHORS COPYING ChangeLog NEWS README 58 | %{_includedir}/SerialPort.h 59 | %{_includedir}/SerialPortConstants.h 60 | %{_includedir}/SerialStream.h 61 | %{_includedir}/SerialStreamBuf.h 62 | %{_libdir}/libserial.a 63 | %{_libdir}/libserial.la 64 | %{_libdir}/libserial.so 65 | %{_libdir}/libserial.so.0 66 | %{_libdir}/libserial.so.0.0.0 67 | 68 | %changelog 69 | -------------------------------------------------------------------------------- /m4/ax_cxx_compile_stdcxx_11.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================ 2 | # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html 3 | # ============================================================================ 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the C++11 12 | # standard; if necessary, add switches to CXXFLAGS to enable support. 13 | # 14 | # The first argument, if specified, indicates whether you insist on an 15 | # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. 16 | # -std=c++11). If neither is specified, you get whatever works, with 17 | # preference for an extended mode. 18 | # 19 | # The second argument, if specified 'mandatory' or if left unspecified, 20 | # indicates that baseline C++11 support is required and that the macro 21 | # should error out if no mode with that support is found. If specified 22 | # 'optional', then configuration proceeds regardless, after defining 23 | # HAVE_CXX11 if and only if a supporting mode is found. 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2008 Benjamin Kosnik 28 | # Copyright (c) 2012 Zack Weinberg 29 | # Copyright (c) 2013 Roy Stogner 30 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 31 | # 32 | # Copying and distribution of this file, with or without modification, are 33 | # permitted in any medium without royalty provided the copyright notice 34 | # and this notice are preserved. This file is offered as-is, without any 35 | # warranty. 36 | 37 | #serial 11 38 | 39 | m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ 40 | template 41 | struct check 42 | { 43 | static_assert(sizeof(int) <= sizeof(T), "not big enough"); 44 | }; 45 | 46 | struct Base { 47 | virtual void f() {} 48 | }; 49 | struct Child : public Base { 50 | virtual void f() override {} 51 | }; 52 | 53 | typedef check> right_angle_brackets; 54 | 55 | int a; 56 | decltype(a) b; 57 | 58 | typedef check check_type; 59 | check_type c; 60 | check_type&& cr = static_cast(c); 61 | 62 | auto d = a; 63 | auto l = [](){}; 64 | // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] 65 | struct use_l { use_l() { l(); } }; 66 | 67 | // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae 68 | // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this 69 | namespace test_template_alias_sfinae { 70 | struct foo {}; 71 | 72 | template 73 | using member = typename T::member_type; 74 | 75 | template 76 | void func(...) {} 77 | 78 | template 79 | void func(member*) {} 80 | 81 | void test(); 82 | 83 | void test() { 84 | func(0); 85 | } 86 | } 87 | ]]) 88 | 89 | AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl 90 | m4_if([$1], [], [], 91 | [$1], [ext], [], 92 | [$1], [noext], [], 93 | [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl 94 | m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], 95 | [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], 96 | [$2], [optional], [ax_cxx_compile_cxx11_required=false], 97 | [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) 98 | AC_LANG_PUSH([C++])dnl 99 | ac_success=no 100 | AC_CACHE_CHECK(whether $CXX supports C++11 features by default, 101 | ax_cv_cxx_compile_cxx11, 102 | [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 103 | [ax_cv_cxx_compile_cxx11=yes], 104 | [ax_cv_cxx_compile_cxx11=no])]) 105 | if test x$ax_cv_cxx_compile_cxx11 = xyes; then 106 | ac_success=yes 107 | fi 108 | 109 | m4_if([$1], [noext], [], [dnl 110 | if test x$ac_success = xno; then 111 | for switch in -std=gnu++11 -std=gnu++0x; do 112 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) 113 | AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, 114 | $cachevar, 115 | [ac_save_CXXFLAGS="$CXXFLAGS" 116 | CXXFLAGS="$CXXFLAGS $switch" 117 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 118 | [eval $cachevar=yes], 119 | [eval $cachevar=no]) 120 | CXXFLAGS="$ac_save_CXXFLAGS"]) 121 | if eval test x\$$cachevar = xyes; then 122 | CXXFLAGS="$CXXFLAGS $switch" 123 | ac_success=yes 124 | break 125 | fi 126 | done 127 | fi]) 128 | 129 | m4_if([$1], [ext], [], [dnl 130 | if test x$ac_success = xno; then 131 | dnl HP's aCC needs +std=c++11 according to: 132 | dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf 133 | for switch in -std=c++11 -std=c++0x +std=c++11; do 134 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) 135 | AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, 136 | $cachevar, 137 | [ac_save_CXXFLAGS="$CXXFLAGS" 138 | CXXFLAGS="$CXXFLAGS $switch" 139 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 140 | [eval $cachevar=yes], 141 | [eval $cachevar=no]) 142 | CXXFLAGS="$ac_save_CXXFLAGS"]) 143 | if eval test x\$$cachevar = xyes; then 144 | CXXFLAGS="$CXXFLAGS $switch" 145 | ac_success=yes 146 | break 147 | fi 148 | done 149 | fi]) 150 | AC_LANG_POP([C++]) 151 | if test x$ax_cxx_compile_cxx11_required = xtrue; then 152 | if test x$ac_success = xno; then 153 | AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) 154 | fi 155 | else 156 | if test x$ac_success = xno; then 157 | HAVE_CXX11=0 158 | AC_MSG_NOTICE([No compiler with C++11 support was found]) 159 | else 160 | HAVE_CXX11=1 161 | AC_DEFINE(HAVE_CXX11,1, 162 | [define if the compiler supports basic C++11 syntax]) 163 | fi 164 | 165 | AC_SUBST(HAVE_CXX11) 166 | fi 167 | ]) 168 | -------------------------------------------------------------------------------- /packaging/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CPACK_PACKAGE_NAME "libserial") 2 | set(CPACK_PACKAGE_CONTACT "crayzeewulf@gmail.com") 3 | set(CPACK_PACKAGE_VENDOR "LibSerial developers, testers, users and contibutors") 4 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Linux serial port programming library for C++") 5 | set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) 6 | set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) 7 | set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) 8 | set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) 9 | set(CPACK_VERBATIM_VARIABLES YES) 10 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_LIST_DIR}/package_desc.txt") 11 | set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE.txt") 12 | set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md") 13 | 14 | set(CPACK_RPM_FILE_NAME RPM-DEFAULT) 15 | set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) 16 | 17 | include(CPack) 18 | -------------------------------------------------------------------------------- /packaging/package_desc.txt: -------------------------------------------------------------------------------- 1 | Package description goes here. 2 | -------------------------------------------------------------------------------- /sip/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_LIBRARY(libserialmod SHARED 2 | SerialPort.sip 3 | SerialPortConstants.sip 4 | exception.sip 5 | libserial.sip 6 | stdexcept.sip 7 | string.sip 8 | vector.sip 9 | ) 10 | 11 | SET_TARGET_PROPERTIES(libserialmod PROPERTIES PREFIX "") 12 | 13 | TARGET_LINK_LIBRARIES(libserialmod 14 | libserial_static 15 | ) 16 | 17 | INSTALL(TARGETS libserialmod 18 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 19 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 20 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 21 | 22 | # TODO - Generate the SIP output with CMake: 23 | #ADD_CUSTOM_COMMAND(OUTPUT 24 | # ${CMAKE_CURRENT_BINARY_DIR}/SerialPort.h 25 | # COMMAND ${SIP_EXECUTABLE} -c ${CMAKE_CURRENT_BINARY_DIR} 26 | # ${CMAKE_CURRENT_SOURCE_DIR}/SerialPort.sip 27 | # DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/SerialPort.sip 28 | # COMMENT "Processing ${CMAKE_CURRENT_SOURCE_DIR}/SerialPort.sip" 29 | # VERBATIM 30 | # ) 31 | -------------------------------------------------------------------------------- /sip/Makefile.am: -------------------------------------------------------------------------------- 1 | SIPFILES = \ 2 | @srcdir@/SerialPort.sip \ 3 | @srcdir@/SerialPortConstants.sip \ 4 | @srcdir@/exception.sip \ 5 | @srcdir@/libserial.sip \ 6 | @srcdir@/stdexcept.sip \ 7 | @srcdir@/string.sip \ 8 | @srcdir@/vector.sip 9 | 10 | EXTRA_DIST = \ 11 | configure.py.in \ 12 | recv_test.py \ 13 | send_test.py \ 14 | $(SIPFILES) 15 | 16 | all: libserialmod.so 17 | 18 | libserialmod.so: Makefile.sip @top_builddir@/src/libserial.la 19 | make -f Makefile.sip 20 | 21 | Makefile.sip: configure.py $(SIPFILES) 22 | python3 ./configure.py 23 | 24 | clean-local: Makefile.sip 25 | make -f Makefile.sip clean 26 | 27 | CLEANFILES = \ 28 | Makefile.sip \ 29 | libserial.sbf \ 30 | sipAPIlibserial.h \ 31 | siplibserialLibSerial.cpp \ 32 | siplibserialLibSerialBaudRate.cpp \ 33 | siplibserialLibSerialCharacterSize.cpp \ 34 | siplibserialLibSerialFlowControl.cpp \ 35 | siplibserialLibSerialParity.cpp \ 36 | siplibserialLibSerialStopBits.cpp \ 37 | siplibserialSerialPort.cpp \ 38 | siplibserialcmodule.cpp \ 39 | siplibserialstd.cpp \ 40 | siplibserialstdexception.cpp \ 41 | siplibserialstdinvalid_argument.cpp \ 42 | siplibserialstdios_base \ 43 | siplibserialstdlogic_error.cpp \ 44 | siplibserialstdruntime_error.cpp \ 45 | siplibserialstdstring.cpp \ 46 | siplibserialstdvector1300.cpp \ 47 | siplibserialstdvector1800.cpp \ 48 | siplibserialstdvector1900.cpp \ 49 | siplibserialstdvector2400.cpp 50 | -------------------------------------------------------------------------------- /sip/SerialPort.sip: -------------------------------------------------------------------------------- 1 | class SerialPort 2 | { 3 | 4 | %TypeHeaderCode 5 | #include 6 | using namespace LibSerial; 7 | %End 8 | 9 | public: 10 | explicit SerialPort(); 11 | 12 | explicit SerialPort(const std::string& fileName, 13 | const LibSerial::BaudRate& baudRate = LibSerial::BaudRate::BAUD_DEFAULT, 14 | const LibSerial::CharacterSize& characterSize = LibSerial::CharacterSize::CHAR_SIZE_DEFAULT, 15 | const LibSerial::FlowControl& flowControlType = LibSerial::FlowControl::FLOW_CONTROL_DEFAULT, 16 | const LibSerial::Parity& parityType = LibSerial::Parity::PARITY_DEFAULT, 17 | const LibSerial::StopBits& stopBits = LibSerial::StopBits::STOP_BITS_DEFAULT); 18 | 19 | virtual ~SerialPort(); 20 | 21 | void 22 | Open(const std::string& fileName, 23 | std::ios_base::openmode openMode = std::ios_base::in | std::ios_base::out); 24 | 25 | void 26 | Close(); 27 | 28 | void 29 | FlushInputBuffer(); 30 | 31 | void 32 | FlushOutputBuffer(); 33 | 34 | void 35 | FlushIOBuffers(); 36 | 37 | bool 38 | IsDataAvailable(); 39 | 40 | bool 41 | IsOpen(); 42 | 43 | void 44 | SetDefaultSerialPortParameters(); 45 | 46 | void 47 | SetBaudRate(const LibSerial::BaudRate baudRate); 48 | 49 | LibSerial::BaudRate 50 | GetBaudRate(); 51 | 52 | void 53 | SetCharacterSize(const LibSerial::CharacterSize characterSize); 54 | 55 | LibSerial::CharacterSize 56 | GetCharacterSize(); 57 | 58 | void 59 | SetFlowControl(const LibSerial::FlowControl flowControlType); 60 | 61 | LibSerial::FlowControl 62 | GetFlowControl(); 63 | 64 | void 65 | SetParity(const LibSerial::Parity parityType); 66 | 67 | LibSerial::Parity 68 | GetParity(); 69 | 70 | void 71 | SetStopBits(const LibSerial::StopBits stopBits); 72 | 73 | LibSerial::StopBits 74 | GetStopBits(); 75 | 76 | void 77 | SetVMin(const short vmin); 78 | 79 | short 80 | GetVMin(); 81 | 82 | void 83 | SetVTime(const short vtime); 84 | 85 | short 86 | GetVTime(); 87 | 88 | void 89 | SetDTR(const bool dtrState = true); 90 | 91 | bool 92 | GetDTR(); 93 | 94 | void 95 | SetRTS(const bool rtsState = true); 96 | 97 | bool 98 | GetRTS(); 99 | 100 | bool 101 | GetCTS(); 102 | 103 | bool 104 | GetDSR(); 105 | 106 | int 107 | GetFileDescriptor(); 108 | 109 | // NOTE: There is not a Python equivalent to std::vector. 110 | // std::vector 111 | // GetAvailableSerialPorts(); 112 | 113 | void 114 | Read(LibSerial::DataBuffer& dataBuffer, 115 | const unsigned int numOfBytes = 0, 116 | const unsigned int msTimeout = 0); 117 | 118 | void 119 | Read(std::string& dataString, 120 | const unsigned int numberOfBytes = 0, 121 | const unsigned int msTimeout = 0); 122 | 123 | void 124 | ReadByte(unsigned char& charBuffer, 125 | const unsigned int msTimeout = 0); 126 | 127 | // NOTE: Python3 provides a mechanism for method overloading, however Python2 does not. 128 | // void 129 | // ReadByte(char& charBuffer, 130 | // const unsigned int msTimeout = 0); 131 | 132 | void 133 | ReadLine(std::string& dataString, 134 | const char lineTerminator = 10, // Sip does not like '\n' 135 | const unsigned int msTimeout = 0); 136 | 137 | void 138 | Write(const LibSerial::DataBuffer& dataBuffer); 139 | 140 | void 141 | Write(const std::string& dataString); 142 | 143 | void 144 | WriteByte(const char charbuffer); 145 | 146 | // NOTE: Python3 provides a mechanism for method overloading, however Python2 does not. 147 | // void 148 | // WriteByte(const unsigned char charbuffer); 149 | 150 | private: 151 | SerialPort(const SerialPort& otherSerialPort); 152 | } ; 153 | -------------------------------------------------------------------------------- /sip/SerialPortConstants.sip: -------------------------------------------------------------------------------- 1 | namespace LibSerial 2 | { 3 | 4 | %TypeHeaderCode 5 | #include 6 | %End 7 | 8 | typedef std::vector DataBuffer; 9 | 10 | namespace BaudRate 11 | { 12 | enum 13 | { 14 | BAUD_50 = B50, 15 | BAUD_75 = B75, 16 | BAUD_110 = B110, 17 | BAUD_134 = B134, 18 | BAUD_150 = B150, 19 | BAUD_200 = B200, 20 | BAUD_300 = B300, 21 | BAUD_600 = B600, 22 | BAUD_1200 = B1200, 23 | BAUD_1800 = B1800, 24 | BAUD_2400 = B2400, 25 | BAUD_4800 = B4800, 26 | BAUD_9600 = B9600, 27 | BAUD_19200 = B19200, 28 | BAUD_38400 = B38400, 29 | BAUD_57600 = B57600, 30 | BAUD_115200 = B115200, 31 | BAUD_230400 = B230400, 32 | BAUD_DEFAULT = BAUD_115200 33 | } ; 34 | }; 35 | 36 | namespace CharacterSize 37 | { 38 | enum 39 | { 40 | CHAR_SIZE_5 = CS5, // !< 5 bit characters. 41 | CHAR_SIZE_6 = CS6, // !< 6 bit characters. 42 | CHAR_SIZE_7 = CS7, // !< 7 bit characters. 43 | CHAR_SIZE_8 = CS8, // !< 8 bit characters. 44 | CHAR_SIZE_DEFAULT = CS8 // !< 8 bit characters. 45 | } ; 46 | }; 47 | 48 | namespace FlowControl 49 | { 50 | enum 51 | { 52 | FLOW_CONTROL_HARDWARE, 53 | FLOW_CONTROL_SOFTWARE, 54 | FLOW_CONTROL_NONE, 55 | FLOW_CONTROL_DEFAULT = FLOW_CONTROL_NONE 56 | }; 57 | }; 58 | 59 | namespace Parity 60 | { 61 | enum 62 | { 63 | PARITY_EVEN, // Even parity. 64 | PARITY_ODD, // Odd parity. 65 | PARITY_NONE, // No parity i.e. parity checking disabled. 66 | PARITY_DEFAULT = PARITY_NONE // No parity i.e. parity checking disabled. 67 | }; 68 | }; 69 | 70 | namespace StopBits 71 | { 72 | enum 73 | { 74 | STOP_BITS_1, // 1 stop bit. 75 | STOP_BITS_2, // 2 stop bits. 76 | STOP_BITS_DEFAULT = STOP_BITS_1 // 1 stop bit. 77 | }; 78 | }; 79 | 80 | }; // namespace LibSerial 81 | -------------------------------------------------------------------------------- /sip/configure.py.in: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import os 3 | import sys 4 | import logging 5 | import optparse 6 | import sipconfig 7 | 8 | def create_options_parser(): 9 | """Create a parser to extract value from command line options.""" 10 | parser = optparse.OptionParser( usage = "python3 %prog [opts]" ) 11 | parser.add_option( "-t", "--otdir", 12 | action = "store", 13 | type = "string", 14 | help = "Path to libserial C++ library installation" ) 15 | return parser 16 | 17 | def main(): 18 | # 19 | # Parse the command line options specified by the user. 20 | # 21 | parser = create_options_parser() 22 | (options, arguments) = parser.parse_args() 23 | # 24 | # The name of the build file generated by SIP and used by the 25 | # build system. 26 | # 27 | build_file = "libserial.sbf" 28 | logging.info( "Build file is " + build_file ) 29 | # 30 | # Get the configuration information for the local SIP installation. 31 | # 32 | logging.info( "Reading sip configuration." ) 33 | config = sipconfig.Configuration() 34 | config.qt_framework = None 35 | # 36 | # Construct and run SIP to generate the module's C++ code. 37 | # 38 | sip_command = " ".join( [ config.sip_bin, 39 | "-c", ".", 40 | "-e", 41 | "-b", build_file, 42 | "@srcdir@/libserial.sip" ] ) 43 | logging.info( "Running sip command: '" + sip_command + "'" ) 44 | os.system( sip_command ) 45 | # 46 | # Create the Makefile with threading support as the libserial libraries 47 | # use threads implicitly. 48 | # 49 | makefile = sipconfig.SIPModuleMakefile( config, 50 | build_file=build_file, 51 | threaded=1, 52 | makefile="Makefile.sip" ) 53 | # 54 | # Add extra cxxflags to be passed to C++ compiler 55 | # 56 | makefile.extra_cxxflags = [ "-std=c++14" ] 57 | # 58 | # Add the library we are wrapping. The name doesn't include any platform 59 | # specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the 60 | # ".dll" extension on Windows). 61 | # 62 | makefile.extra_include_dirs = [ "@top_srcdir@/src" ] 63 | makefile.extra_lib_dirs = [ "@top_builddir@/src/.libs" ] 64 | makefile.extra_libs = [ "serial" ] 65 | # 66 | # Generate the Makefile itself. 67 | # 68 | makefile.generate() 69 | ############################################################################### 70 | # The script starts here. 71 | ############################################################################### 72 | 73 | if __name__ == "__main__": 74 | try: 75 | logging.basicConfig( level = logging.DEBUG, 76 | format = '%(asctime)s %(levelname)s %(message)s' ) 77 | main() 78 | except SystemExit: 79 | raise 80 | except: 81 | print("An internal error occured. Please report all the output from the program, including the following traceback.") 82 | raise 83 | -------------------------------------------------------------------------------- /sip/exception.sip: -------------------------------------------------------------------------------- 1 | namespace std 2 | { 3 | class exception 4 | { 5 | %TypeHeaderCode 6 | #include 7 | %End 8 | public: 9 | exception() throw(); 10 | 11 | virtual ~exception() throw(); 12 | 13 | virtual const char* what() const throw(); 14 | }; 15 | }; -------------------------------------------------------------------------------- /sip/iosbase.sip: -------------------------------------------------------------------------------- 1 | namespace std 2 | { 3 | class ios_base /Abstract/ 4 | { 5 | %TypeHeaderCode 6 | #include 7 | %End 8 | 9 | public: 10 | 11 | // Define openmode flags 12 | enum openmode 13 | { 14 | binary = 0x01, 15 | app = 0x02, 16 | in = 0x04, 17 | out = 0x08, 18 | trunc = 0x10, 19 | ate = 0x20 20 | }; 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /sip/libserial.sip: -------------------------------------------------------------------------------- 1 | %Module libserial 2 | 3 | %Include SerialPort.sip 4 | %Include SerialPortConstants.sip 5 | 6 | %Include exception.sip 7 | %Include iosbase.sip 8 | %Include stdexcept.sip 9 | %Include string.sip 10 | %Include vector.sip 11 | -------------------------------------------------------------------------------- /sip/recv_test.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from libserial import SerialPort 3 | import errno 4 | import sys 5 | 6 | def main(): 7 | serial_port = SerialPort( "/dev/ttyUSB11" ) 8 | serial_port.Open( SerialPort.BAUD_115200, 9 | SerialPort.CHAR_SIZE_DEFAULT, 10 | SerialPort.PARITY_DEFAULT, 11 | SerialPort.STOP_BITS_DEFAULT, 12 | SerialPort.FLOW_CONTROL_HARD ) 13 | try: 14 | while True: 15 | sys.stdout.write( serial_port.ReadByte() ) 16 | except IOError, (errorNumber, errorMessage): 17 | if ( errno.EINTR == errorNumber ): 18 | print() 19 | print("Ignoring EINTR.") 20 | pass 21 | else: 22 | raise 23 | except KeyboardInterrupt: 24 | sys.exit(0) 25 | 26 | if __name__ == "__main__": 27 | main() 28 | -------------------------------------------------------------------------------- /sip/send_test.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import sys 3 | import libserial 4 | 5 | def main(): 6 | serial_port = libserial.SerialPort( "/dev/ttyUSB0" ) 7 | serial_port.Open( libserial.SerialPort.BAUD_115200, 8 | libserial.SerialPort.CHAR_SIZE_DEFAULT, 9 | libserial.SerialPort.PARITY_DEFAULT, 10 | libserial.SerialPort.STOP_BITS_DEFAULT, 11 | libserial.SerialPort.FLOW_CONTROL_HARD ) 12 | try: 13 | while True: 14 | for i in range( 65, 91 ): 15 | serial_port.WriteByte( chr(i) ) 16 | sys.stdout.write( chr(i) ) 17 | except KeyboardInterrupt: 18 | sys.exit(0) 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /sip/stdexcept.sip: -------------------------------------------------------------------------------- 1 | namespace std 2 | { 3 | %TypeHeaderCode 4 | #include 5 | %End 6 | class logic_error : std::exception 7 | { 8 | public: 9 | explicit logic_error(const std::string& __arg); 10 | 11 | virtual ~logic_error() throw(); 12 | 13 | virtual const char* what() const throw(); 14 | }; 15 | 16 | class runtime_error : std::exception 17 | { 18 | public: 19 | explicit runtime_error(const std::string& __arg); 20 | 21 | virtual ~runtime_error() throw(); 22 | 23 | virtual const char* what() const throw(); 24 | }; 25 | 26 | class invalid_argument : std::logic_error 27 | { 28 | public: 29 | explicit invalid_argument(const std::string& __arg); 30 | 31 | virtual ~invalid_argument() throw(); 32 | %MethodCode 33 | return; 34 | %End 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /sip/string.sip: -------------------------------------------------------------------------------- 1 | %MappedType std::string 2 | { 3 | %TypeHeaderCode 4 | #include 5 | #include 6 | %End 7 | 8 | %ConvertToTypeCode 9 | 10 | // If sipIsErr is NULL then we must check the type of the 11 | // Python object and return the result. 12 | if ( ! sipIsErr ) 13 | { 14 | return PyUnicode_Check(PyObject_Str( sipPy )); 15 | } 16 | 17 | char *str_val = 0 ; 18 | 19 | if ( PyArg_Parse( sipPy, "s", &str_val ) ) 20 | { 21 | std::string* ret_val = new std::string( str_val ); 22 | if ( 0 == ret_val ) 23 | { 24 | *sipIsErr = 1; 25 | return 0 ; 26 | } 27 | *sipCppPtr = ret_val; 28 | } 29 | else 30 | { 31 | *sipIsErr = 1 ; 32 | return 0 ; 33 | } 34 | 35 | return sipGetState( sipTransferObj ); 36 | %End 37 | 38 | %ConvertFromTypeCode 39 | 40 | // Inspired by QtCore/qstring.cpp from PyQt4 source code. 41 | PyObject *uobj = 42 | PyUnicode_FromUnicode( NULL, sipCpp->length() ); 43 | 44 | if ( 0 == uobj ) 45 | { 46 | return 0; 47 | } 48 | 49 | Py_UNICODE *pyu = PyUnicode_AS_UNICODE( uobj ); 50 | 51 | for( unsigned int i=0; ilength(); ++i, ++pyu ) 52 | { 53 | *pyu = sipCpp->at(i); 54 | } 55 | 56 | return uobj; 57 | %End 58 | }; 59 | 60 | -------------------------------------------------------------------------------- /sip/test_control_lines.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from libserial import SerialPort 3 | from time import sleep 4 | import optparse 5 | import logging 6 | 7 | def create_options_parser(): 8 | """Create a parser to extract value from command line options.""" 9 | parser = optparse.OptionParser( usage = "%prog [opts]" ) 10 | parser.add_option( "-d", "--device", 11 | action = "store", 12 | type = "string", 13 | help = "Serial port device", 14 | default = "/dev/ttyS0" ) 15 | return parser 16 | 17 | 18 | def main(): 19 | # 20 | # Parse the command line options specified by the user. 21 | # 22 | parser = create_options_parser() 23 | (options, arguments) = parser.parse_args() 24 | # 25 | logging.info( "Opening serial port " + options.device ) 26 | serial_port = SerialPort( options.device ) 27 | serial_port.Open( SerialPort.BAUD_DEFAULT, 28 | SerialPort.CHAR_SIZE_DEFAULT, 29 | SerialPort.PARITY_DEFAULT, 30 | SerialPort.STOP_BITS_DEFAULT, 31 | SerialPort.FLOW_CONTROL_NONE ) 32 | while True: 33 | # 34 | serial_port.SetRts( True ) 35 | serial_port.SetDtr( False ) 36 | # 37 | assert ( True == serial_port.GetRts() ) 38 | assert ( False == serial_port.GetDtr() ) 39 | # 40 | sleep(1) 41 | # 42 | serial_port.SetRts( False ) 43 | serial_port.SetDtr( True ) 44 | # 45 | assert ( False == serial_port.GetRts() ) 46 | assert ( True == serial_port.GetDtr() ) 47 | # 48 | sleep(1) 49 | ############################################################################### 50 | # The script starts here. 51 | ############################################################################### 52 | 53 | if __name__ == "__main__": 54 | try: 55 | logging.basicConfig( level = logging.DEBUG, 56 | format = '%(asctime)s %(levelname)s %(message)s' ) 57 | main() 58 | except SystemExit: 59 | raise 60 | except: 61 | print \ 62 | """An internal error occured. Please report all the output from the program, 63 | including the following traceback. 64 | """ 65 | raise 66 | -------------------------------------------------------------------------------- /sip/vector.sip: -------------------------------------------------------------------------------- 1 | // SIP support for std::vector 2 | // by Giovanni Bajo develer.com> 3 | // Public domain 4 | // 5 | // http://github.com/kevinwatters/wxpy/tree/master%2Fsrc%2Fvector.sip?raw=true 6 | // 7 | // **************************************************** 8 | // SIP generic implementation for std::vector<> 9 | // **************************************************** 10 | // 11 | // Alas, this template-based generic implementation is valid only if 12 | // the element type is a SIP-wrapped type. For basic types (int, 13 | // double, etc.) we are forced to cut & paste to provide a 14 | // specialization. 15 | // 16 | 17 | template 18 | %MappedType std::vector 19 | { 20 | %TypeHeaderCode 21 | #include 22 | %End 23 | 24 | %ConvertFromTypeCode 25 | PyObject *l; 26 | 27 | // Create the Python list of the correct length. 28 | if ((l = PyList_New(sipCpp -> size())) == NULL) 29 | return NULL; 30 | 31 | // Go through each element in the C++ instance and convert it to a 32 | // wrapped P2d. 33 | for (int i = 0; i < (int)sipCpp -> size(); ++i) 34 | { 35 | TYPE *cpp = new TYPE(sipCpp -> at(i)); 36 | PyObject *pobj; 37 | 38 | // Get the Python wrapper for the Type instance, creating a new 39 | // one if necessary, and handle any ownership transfer. 40 | if ((pobj = sipConvertFromInstance(cpp, sipClass_TYPE, sipTransferObj)) == NULL) 41 | { 42 | // There was an error so garbage collect the Python list. 43 | Py_DECREF(l); 44 | return NULL; 45 | } 46 | 47 | // Add the wrapper to the list. 48 | PyList_SET_ITEM(l, i, pobj); 49 | } 50 | 51 | // Return the Python list. 52 | return l; 53 | %End 54 | 55 | %ConvertToTypeCode 56 | // Check if type is compatible 57 | if (sipIsErr == NULL) 58 | { 59 | // Must be any iterable 60 | PyObject *i = PyObject_GetIter(sipPy); 61 | bool iterable = (i != NULL); 62 | Py_XDECREF(i); 63 | return iterable; 64 | } 65 | 66 | // Iterate over the object 67 | PyObject *iterator = PyObject_GetIter(sipPy); 68 | PyObject *item; 69 | 70 | std::vector *V = new std::vector(); 71 | 72 | while ((item = PyIter_Next(iterator))) 73 | { 74 | if (!sipCanConvertToInstance(item, sipClass_TYPE, SIP_NOT_NONE)) 75 | { 76 | PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to TYPE"); 77 | *sipIsErr = 1; 78 | break; 79 | } 80 | 81 | int state; 82 | TYPE* p = reinterpret_cast( 83 | sipConvertToInstance(item, sipClass_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr)); 84 | 85 | if (!*sipIsErr) 86 | V->push_back(*p); 87 | 88 | sipReleaseInstance(p, sipClass_TYPE, state); 89 | Py_DECREF(item); 90 | } 91 | 92 | Py_DECREF(iterator); 93 | 94 | if (*sipIsErr) 95 | { 96 | delete V; 97 | return 0; 98 | } 99 | 100 | *sipCppPtr = V; 101 | return sipGetState(sipTransferObj); 102 | %End 103 | }; 104 | 105 | // **************************************************** 106 | // Specialization for std::vector 107 | // **************************************************** 108 | 109 | %MappedType std::vector 110 | { 111 | %TypeHeaderCode 112 | #include 113 | %End 114 | 115 | %ConvertFromTypeCode 116 | PyObject *l; 117 | 118 | // Create the Python list of the correct length. 119 | if ((l = PyList_New(sipCpp -> size())) == NULL) 120 | return NULL; 121 | 122 | // Go through each element in the C++ instance and convert it to a 123 | // wrapped object. 124 | for (int i = 0; i < (int)sipCpp -> size(); ++i) 125 | { 126 | // Add the wrapper to the list. 127 | PyList_SET_ITEM(l, i, PyFloat_FromDouble(sipCpp -> at(i))); 128 | } 129 | 130 | // Return the Python list. 131 | return l; 132 | %End 133 | 134 | %ConvertToTypeCode 135 | // Check if type is compatible 136 | if (sipIsErr == NULL) 137 | { 138 | // Must be any iterable 139 | PyObject *i = PyObject_GetIter(sipPy); 140 | bool iterable = (i != NULL); 141 | Py_XDECREF(i); 142 | return iterable; 143 | } 144 | 145 | // Iterate over the object 146 | PyObject *iterator = PyObject_GetIter(sipPy); 147 | PyObject *item; 148 | 149 | // Maximum number of elements 150 | int len = PyObject_Size(sipPy); 151 | std::vector *V = new std::vector(); 152 | V->reserve(len); 153 | 154 | if (len) 155 | { 156 | while ((item = PyIter_Next(iterator))) 157 | { 158 | if (!PyNumber_Check(item)) 159 | { 160 | PyErr_Format(PyExc_TypeError, "object in iterable is not a number"); 161 | *sipIsErr = 1; 162 | break; 163 | } 164 | 165 | PyObject *f = PyNumber_Float(item); 166 | V->push_back(PyFloat_AsDouble(f)); 167 | 168 | Py_DECREF(f); 169 | Py_DECREF(item); 170 | } 171 | 172 | Py_DECREF(iterator); 173 | 174 | if (*sipIsErr) 175 | { 176 | delete V; 177 | return 0; 178 | } 179 | } 180 | 181 | *sipCppPtr = V; 182 | return sipGetState(sipTransferObj); 183 | %End 184 | }; 185 | 186 | // **************************************************** 187 | // Specialization for std::vector 188 | // **************************************************** 189 | 190 | %MappedType std::vector 191 | { 192 | %TypeHeaderCode 193 | #include 194 | %End 195 | 196 | %ConvertFromTypeCode 197 | PyObject *l; 198 | 199 | // Create the Python list of the correct length. 200 | if ((l = PyList_New(sipCpp -> size())) == NULL) 201 | return NULL; 202 | 203 | // Go through each element in the C++ instance and convert it to a 204 | // wrapped object. 205 | for (int i = 0; i < (int)sipCpp -> size(); ++i) 206 | { 207 | // Add the wrapper to the list. 208 | PyList_SET_ITEM(l, i, PyLong_FromLong(sipCpp -> at(i))); 209 | } 210 | 211 | // Return the Python list. 212 | return l; 213 | %End 214 | 215 | %ConvertToTypeCode 216 | // Check if type is compatible 217 | if (sipIsErr == NULL) 218 | { 219 | // Must be any iterable 220 | PyObject *i = PyObject_GetIter(sipPy); 221 | bool iterable = (i != NULL); 222 | Py_XDECREF(i); 223 | return iterable; 224 | } 225 | 226 | // Iterate over the object 227 | PyObject *iterator = PyObject_GetIter(sipPy); 228 | PyObject *item; 229 | 230 | // Maximum number of elements 231 | int len = PyObject_Size(sipPy); 232 | std::vector *V = new std::vector(); 233 | V->reserve(len); 234 | 235 | if (len) 236 | { 237 | while ((item = PyIter_Next(iterator))) 238 | { 239 | if (!PyLong_Check(item)) 240 | { 241 | PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float"); 242 | *sipIsErr = 1; 243 | break; 244 | } 245 | 246 | int val = PyLong_AsLong(item); 247 | V->push_back(val); 248 | 249 | Py_DECREF(item); 250 | } 251 | 252 | Py_DECREF(iterator); 253 | 254 | if (*sipIsErr) 255 | { 256 | delete V; 257 | return 0; 258 | } 259 | } 260 | 261 | *sipCppPtr = V; 262 | return sipGetState(sipTransferObj); 263 | %End 264 | }; 265 | 266 | 267 | // **************************************************** 268 | // Specialization for std::vector 269 | // **************************************************** 270 | 271 | %MappedType std::vector 272 | { 273 | %TypeHeaderCode 274 | #include 275 | %End 276 | 277 | %ConvertFromTypeCode 278 | PyObject *l; 279 | 280 | // Create the Python list of the correct length. 281 | if ((l = PyList_New(sipCpp -> size())) == NULL) 282 | return NULL; 283 | 284 | // Go through each element in the C++ instance and convert it to a 285 | // wrapped object. 286 | for (int i = 0; i < (int)sipCpp -> size(); ++i) 287 | { 288 | // Add the wrapper to the list. 289 | PyList_SET_ITEM(l, i, PyLong_FromLong(sipCpp -> at(i))); 290 | } 291 | 292 | // Return the Python list. 293 | return l; 294 | %End 295 | 296 | %ConvertToTypeCode 297 | // Check if type is compatible 298 | if (sipIsErr == NULL) 299 | { 300 | // Must be any iterable 301 | PyObject *i = PyObject_GetIter(sipPy); 302 | bool iterable = (i != NULL); 303 | Py_XDECREF(i); 304 | return iterable; 305 | } 306 | 307 | // Iterate over the object 308 | PyObject *iterator = PyObject_GetIter(sipPy); 309 | PyObject *item; 310 | 311 | // Maximum number of elements 312 | unsigned int len = PyObject_Size(sipPy); 313 | std::vector *V = new std::vector(); 314 | V->reserve(len); 315 | 316 | if (len) 317 | { 318 | while ((item = PyIter_Next(iterator))) 319 | { 320 | if (!PyLong_Check(item)) 321 | { 322 | PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float"); 323 | *sipIsErr = 1; 324 | break; 325 | } 326 | 327 | unsigned int val = PyLong_AsLong(item); 328 | V->push_back(val); 329 | 330 | Py_DECREF(item); 331 | } 332 | 333 | Py_DECREF(iterator); 334 | 335 | if (*sipIsErr) 336 | { 337 | delete V; 338 | return 0; 339 | } 340 | } 341 | 342 | *sipCppPtr = V; 343 | return sipGetState(sipTransferObj); 344 | %End 345 | }; 346 | 347 | // **************************************************** 348 | // Specialization for std::vector 349 | // **************************************************** 350 | 351 | %MappedType std::vector 352 | { 353 | %TypeHeaderCode 354 | #include 355 | %End 356 | 357 | %ConvertFromTypeCode 358 | PyObject *l; 359 | 360 | // Create the Python list of the correct length. 361 | if ((l = PyList_New(sipCpp -> size())) == NULL) 362 | return NULL; 363 | 364 | // Go through each element in the C++ instance and convert it to a 365 | // wrapped object. 366 | for (int i = 0; i < (int)sipCpp -> size(); ++i) 367 | { 368 | // Add the wrapper to the list. 369 | PyList_SET_ITEM(l, i, PyLong_FromLong(sipCpp -> at(i))); 370 | } 371 | 372 | // Return the Python list. 373 | return l; 374 | %End 375 | 376 | %ConvertToTypeCode 377 | // Check if type is compatible 378 | if (sipIsErr == NULL) 379 | { 380 | // Must be any iterable 381 | PyObject *i = PyObject_GetIter(sipPy); 382 | bool iterable = (i != NULL); 383 | Py_XDECREF(i); 384 | return iterable; 385 | } 386 | 387 | // Iterate over the object 388 | PyObject *iterator = PyObject_GetIter(sipPy); 389 | PyObject *item; 390 | 391 | // Maximum number of elements 392 | unsigned int len = PyObject_Size(sipPy); 393 | std::vector *V = new std::vector(); 394 | V->reserve(len); 395 | 396 | if (len) 397 | { 398 | while ((item = PyIter_Next(iterator))) 399 | { 400 | if (!PyLong_Check(item)) 401 | { 402 | PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float"); 403 | *sipIsErr = 1; 404 | break; 405 | } 406 | 407 | unsigned int val = PyLong_AsLong(item); 408 | V->push_back(val); 409 | 410 | Py_DECREF(item); 411 | } 412 | 413 | Py_DECREF(iterator); 414 | 415 | if (*sipIsErr) 416 | { 417 | delete V; 418 | return 0; 419 | } 420 | } 421 | 422 | *sipCppPtr = V; 423 | return sipGetState(sipTransferObj); 424 | %End 425 | }; 426 | -------------------------------------------------------------------------------- /src/.cvsignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .libs 3 | Makefile 4 | Makefile.in 5 | *.lo 6 | lib*.la 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIBSERIAL_SOURCES 2 | SerialPort.cpp 3 | SerialStream.cpp 4 | SerialStreamBuf.cpp) 5 | 6 | add_library(libserial_static STATIC ${LIBSERIAL_SOURCES}) 7 | 8 | # 9 | # We already have "lib" prefix in the target name. Prevent CMake from adding 10 | # another "lib" prefix. 11 | # 12 | set_target_properties(libserial_static PROPERTIES PREFIX "") 13 | target_include_directories(libserial_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 14 | target_link_libraries(libserial_static Threads::Threads) 15 | 16 | # 17 | # Install all our headers under the libserial subfolder of the include 18 | # directory so that our headers do not conflict with similarly named headers 19 | # from other libraries. Clients can either include our headers with libserial 20 | # folder prefixed (for example, "#include ") or put the 21 | # libserial folder in their include path (for example, 22 | # "-I/usr/include/libserial"). 23 | # 24 | install(DIRECTORY libserial 25 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 26 | 27 | # 28 | # The static library is always built as it is needed for unit tests but it is 29 | # installed only if INSTALL_STATIC is set. 30 | # 31 | if (INSTALL_STATIC) 32 | install(TARGETS libserial_static 33 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 34 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 35 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 36 | endif() 37 | # 38 | # Use the same name (libserial) for both the static and shared libraries 39 | # 40 | set_target_properties(libserial_static PROPERTIES OUTPUT_NAME libserial) 41 | 42 | # 43 | # Build and install the shared object library only if INSTALL_SHARED is set. 44 | # 45 | if (INSTALL_SHARED) 46 | add_library(libserial_shared SHARED ${LIBSERIAL_SOURCES}) 47 | set_target_properties(libserial_shared PROPERTIES PREFIX "") 48 | set_target_properties(libserial_shared PROPERTIES OUTPUT_NAME libserial) 49 | target_include_directories(libserial_shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 50 | target_link_libraries(libserial_shared Threads::Threads) 51 | # 52 | # Add version numbering to the shared library. Based on the recommendations in 53 | # the following book: 54 | # 55 | # "Professional CMake: A Practical Guide" --Craig Scott 56 | # (https://crascit.com/professional-cmake/) 57 | # 58 | set_target_properties(libserial_shared PROPERTIES 59 | VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} 60 | SOVERSION ${PROJECT_VERSION_MAJOR} 61 | ) 62 | install(TARGETS libserial_shared 63 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 64 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 65 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 66 | endif() 67 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CXXFLAGS = -Weffc++ 2 | 3 | AM_CPPFLAGS = -I@top_srcdir@/src 4 | 5 | SUBDIRS = libserial 6 | 7 | lib_LTLIBRARIES = libserial.la 8 | 9 | libserial_la_SOURCES = \ 10 | SerialPort.cpp \ 11 | SerialStream.cpp \ 12 | SerialStreamBuf.cpp 13 | 14 | libserialincludedir = @includedir@/libserial 15 | libserialinclude_HEADERS = \ 16 | libserial/SerialPort.h \ 17 | libserial/SerialPortConstants.h \ 18 | libserial/SerialStream.h \ 19 | libserial/SerialStreamBuf.h 20 | 21 | libserial_la_LDFLAGS = -version-info 1:0:0 22 | -------------------------------------------------------------------------------- /src/libserial/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_HEADERS = \ 2 | SerialPort.h \ 3 | SerialPortConstants.h \ 4 | SerialStream.h \ 5 | SerialStreamBuf.h 6 | -------------------------------------------------------------------------------- /src/libserial/SerialPortConstants.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file SerialPortConstants.h * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #pragma once 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | namespace LibSerial 44 | { 45 | /** 46 | * @brief Error messages utilized when throwing exceptions. 47 | */ 48 | const std::string ERR_MSG_INVALID_BAUD_RATE = "Invalid baud rate."; 49 | const std::string ERR_MSG_INVALID_CHARACTER_SIZE = "Invalid character size."; 50 | const std::string ERR_MSG_INVALID_FLOW_CONTROL = "Invalid flow control."; 51 | const std::string ERR_MSG_INVALID_PARITY = "Invalid parity setting."; 52 | const std::string ERR_MSG_INVALID_STOP_BITS = "Invalid number of stop bits."; 53 | const std::string ERR_MSG_READ_TIMEOUT = "Read timeout"; 54 | const std::string ERR_MSG_PORT_ALREADY_OPEN = "Serial port already open."; 55 | const std::string ERR_MSG_PORT_NOT_OPEN = "Serial port not open."; 56 | const std::string ERR_MSG_INVALID_MODEM_LINE = "Invalid modem line." ; 57 | 58 | /** 59 | * @brief Time conversion constants. 60 | */ 61 | constexpr int MICROSECONDS_PER_MS = 1000 ; 62 | constexpr int MILLISECONDS_PER_SEC = 1000 ; 63 | constexpr int MICROSECONDS_PER_SEC = 1000000 ; 64 | 65 | /** 66 | * @brief Bits to bytes conversion constant. 67 | */ 68 | constexpr int BITS_PER_BYTE = 8 ; 69 | 70 | /** 71 | * @brief The default character buffer size. 72 | */ 73 | constexpr short VMIN_DEFAULT = 1 ; 74 | 75 | /** 76 | * @brief The default character buffer timing. 77 | */ 78 | constexpr short VTIME_DEFAULT = 0 ; 79 | 80 | /** 81 | * @brief Character used to signal that I/O can start while using 82 | * software flow control with the serial port. 83 | */ 84 | constexpr char CTRL_Q = 0x11 ; 85 | 86 | /** 87 | * @brief Character used to signal that I/O should stop while using 88 | * software flow control with the serial port. 89 | */ 90 | constexpr char CTRL_S = 0x13 ; 91 | 92 | /** 93 | * @brief Type used to receive and return raw data to/from methods. 94 | */ 95 | using DataBuffer = std::vector ; 96 | 97 | 98 | /** 99 | * @note - For reference, below is a list of std::exception types: 100 | * logic_error 101 | * invalid_argument 102 | * domain_error 103 | * length_error 104 | * out_of_range 105 | * future_error 106 | * runtime_error 107 | * range_error 108 | * overflow_error 109 | * underflow_error 110 | * regex_error 111 | * system_error 112 | * ios_base::failure 113 | * bad_typeid 114 | * bad_cast 115 | * bad_weak_ptr 116 | * bad_function_call 117 | * bad_alloc 118 | * bad_array_new_length 119 | * bad_exception 120 | */ 121 | 122 | /** 123 | * @brief Exception error thrown when the serial port is not open. 124 | */ 125 | class NotOpen : public std::logic_error 126 | { 127 | public: 128 | /** 129 | * @brief Exception error thrown when the serial port is not open. 130 | */ 131 | explicit NotOpen(const std::string& whatArg [[maybe_unused]]) 132 | : logic_error(whatArg) 133 | { 134 | } 135 | } ; 136 | 137 | /** 138 | * @brief Exception error thrown when the serial port is already open. 139 | */ 140 | class AlreadyOpen : public std::logic_error 141 | { 142 | public: 143 | /** 144 | * @brief Exception error thrown when the serial port is already open. 145 | */ 146 | explicit AlreadyOpen(const std::string& whatArg [[maybe_unused]]) 147 | : logic_error(whatArg) 148 | { 149 | } 150 | } ; 151 | 152 | /** 153 | * @brief Exception error thrown when the serial port could not be opened. 154 | */ 155 | class OpenFailed : public std::runtime_error 156 | { 157 | public: 158 | /** 159 | * @brief Exception error thrown when the serial port could not be opened. 160 | */ 161 | explicit OpenFailed(const std::string& whatArg [[maybe_unused]]) 162 | : runtime_error(whatArg) 163 | { 164 | } 165 | } ; 166 | 167 | /** 168 | * @brief Exception error thrown when data could not be read from the 169 | * serial port before the timeout had been exceeded. 170 | */ 171 | class ReadTimeout : public std::runtime_error 172 | { 173 | public: 174 | /** 175 | * @brief Exception error thrown when data could not be read from the 176 | * serial port before the timeout had been exceeded. 177 | */ 178 | explicit ReadTimeout(const std::string& whatArg [[maybe_unused]]) 179 | : runtime_error(whatArg) 180 | { 181 | } 182 | } ; 183 | 184 | /** 185 | * @brief The baud rates currently supported by the Single Unix 186 | * Specification V3 general terminal interface specification. 187 | * Note that B0 is not supported because it not actually a baud 188 | * rate, is used to terminate the connection, (i.e. drop DTR). 189 | * The Close() method should be used instead. 190 | */ 191 | enum class BaudRate : speed_t 192 | { 193 | BAUD_50 = B50, 194 | BAUD_75 = B75, 195 | BAUD_110 = B110, 196 | BAUD_134 = B134, 197 | BAUD_150 = B150, 198 | BAUD_200 = B200, 199 | BAUD_300 = B300, 200 | BAUD_600 = B600, 201 | BAUD_1200 = B1200, 202 | BAUD_1800 = B1800, 203 | BAUD_2400 = B2400, 204 | BAUD_4800 = B4800, 205 | BAUD_9600 = B9600, 206 | BAUD_19200 = B19200, 207 | BAUD_38400 = B38400, 208 | BAUD_57600 = B57600, 209 | BAUD_115200 = B115200, 210 | BAUD_230400 = B230400, 211 | 212 | // @note: >B230400 are defined in Linux but not other POSIX systems, (e.g. Mac OS X). 213 | #ifdef __linux__ 214 | BAUD_460800 = B460800, 215 | BAUD_500000 = B500000, 216 | BAUD_576000 = B576000, 217 | BAUD_921600 = B921600, 218 | BAUD_1000000 = B1000000, 219 | BAUD_1152000 = B1152000, 220 | BAUD_1500000 = B1500000, 221 | #if __MAX_BAUD > B2000000 222 | BAUD_2000000 = B2000000, 223 | BAUD_2500000 = B2500000, 224 | BAUD_3000000 = B3000000, 225 | BAUD_3500000 = B3500000, 226 | BAUD_4000000 = B4000000, 227 | #endif // __MAX_BAUD 228 | #endif // __linux__ 229 | BAUD_DEFAULT = BAUD_115200, 230 | BAUD_INVALID = std::numeric_limits::max() 231 | } ; 232 | 233 | /** 234 | * @brief The allowed character sizes. 235 | */ 236 | enum class CharacterSize : tcflag_t 237 | { 238 | CHAR_SIZE_5 = CS5, // !< 5 bit characters. 239 | CHAR_SIZE_6 = CS6, // !< 6 bit characters. 240 | CHAR_SIZE_7 = CS7, // !< 7 bit characters. 241 | CHAR_SIZE_8 = CS8, // !< 8 bit characters. 242 | CHAR_SIZE_DEFAULT = CS8, // !< 8 bit characters. 243 | CHAR_SIZE_INVALID = std::numeric_limits::max() 244 | } ; 245 | 246 | /** 247 | * @brief The allowed flow control types. 248 | */ 249 | enum class FlowControl : tcflag_t 250 | { 251 | FLOW_CONTROL_HARDWARE, 252 | FLOW_CONTROL_SOFTWARE, 253 | FLOW_CONTROL_NONE, 254 | FLOW_CONTROL_DEFAULT = FLOW_CONTROL_NONE, 255 | FLOW_CONTROL_INVALID = std::numeric_limits::max() 256 | } ; 257 | 258 | /** 259 | * @brief The allowed parity types. 260 | */ 261 | enum class Parity : tcflag_t 262 | { 263 | PARITY_EVEN, // !< Even parity. 264 | PARITY_ODD, // !< Odd parity. 265 | PARITY_NONE, // !< No parity i.e. parity checking disabled. 266 | PARITY_DEFAULT = PARITY_NONE, // !< No parity i.e. parity checking disabled. 267 | PARITY_INVALID = std::numeric_limits::max() // !< Invalid parity value. 268 | } ; 269 | 270 | /** 271 | * @brief The allowed number of stop bits. 272 | */ 273 | enum class StopBits : tcflag_t 274 | { 275 | STOP_BITS_1, // !< 1 stop bit. 276 | STOP_BITS_2, // !< 2 stop bits. 277 | STOP_BITS_DEFAULT = STOP_BITS_1, // !< 1 stop bit. 278 | STOP_BITS_INVALID = std::numeric_limits::max() 279 | } ; 280 | 281 | } // namespace LibSerial 282 | -------------------------------------------------------------------------------- /src/libserial/SerialStream.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file SerialStream.h * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #pragma once 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | namespace LibSerial 43 | { 44 | /** 45 | * @brief SerialStream is a stream class for accessing serial ports on 46 | * POSIX operating systems. A lot of the functionality of this class 47 | * has been obtained by looking at the code of libserial package by 48 | * Linas Vepstas, (linas@linas.org) and the excellent document on 49 | * serial programming by Michael R. Sweet. This document can be 50 | * found at 51 | * 52 | * http://www.easysw.com/~mike/serial/serial.html. 53 | * The libserial package can be found at 54 | * 55 | * http://www.linas.org/serial/. 56 | * This class allows one to set various parameters of a serial 57 | * port and then access it like a simple fstream. (In fact, that 58 | * is exactly what it does!) It sets the parameters of the 59 | * serial port by maintaining a file descriptor for the port and 60 | * uses the basic_fstream functions for the IO. We have not 61 | * implemented any file locking yet but it will be added soon. 62 | * 63 | * Make sure you read the documentation of the standard fstream 64 | * template before using this class because most of the 65 | * functionality is inherited from fstream. Also, a lot of 66 | * information about the various system calls used in the 67 | * implementation can also be found in the Single Unix 68 | * Specification (Version 2). A copy of this document can be 69 | * obtained from 70 | * http://www.UNIX-systems.org/. We will refer to this 71 | * document as SUS-2. 72 | */ 73 | class SerialStream : public std::iostream 74 | { 75 | public: 76 | 77 | /** 78 | * @brief Default Contructor. 79 | * Creates a new SerialStream object but does not open it. 80 | * The Open() method will need to be called explicitly on 81 | * the object to communicate with the serial port. 82 | */ 83 | explicit SerialStream() ; 84 | 85 | /** 86 | * @brief Constructor that allows a SerialStream instance to be 87 | * created and opened, initializing the corresponding 88 | * serial port with the specified parameters. 89 | * Suggested by Witek Adamus (wit3k): 90 | * https://sourceforge.net/tracker/index.php?func=detail&aid=2137885&group_id=9432&atid=359432 91 | * 92 | * @param fileName The file name of the serial stream. 93 | * @param baudRate The communications baud rate. 94 | * @param characterSize The size of the character buffer for 95 | * storing read/write streams. 96 | * @param parityType The parity type for the serial stream. 97 | * @param stopBits The number of stop bits for the serial stream. 98 | * @param flowControlType The flow control type for the serial stream. 99 | * @param exclusive Set exclusive access for the serial stream. 100 | */ 101 | explicit SerialStream(const std::string& fileName, 102 | const BaudRate& baudRate = BaudRate::BAUD_DEFAULT, 103 | const CharacterSize& characterSize = CharacterSize::CHAR_SIZE_DEFAULT, 104 | const FlowControl& flowControlType = FlowControl::FLOW_CONTROL_DEFAULT, 105 | const Parity& parityType = Parity::PARITY_DEFAULT, 106 | const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT, 107 | bool exclusive = true) ; 108 | 109 | /** 110 | * @brief Default Destructor for a SerialStream object 111 | * Closes the stream associated with mFileDescriptor, and 112 | * also closes the serial port if open. 113 | * Remaining actions are accomplished by the fstream destructor. 114 | */ 115 | virtual ~SerialStream() ; 116 | 117 | /** 118 | * @brief Prevents copying of objects of this class by declaring the copy 119 | * constructor private. This method is never defined. 120 | */ 121 | SerialStream(const SerialStream& otherSerialStream) = delete; 122 | 123 | /** 124 | * @brief Move construction is disallowed. 125 | */ 126 | SerialStream(const SerialStream&& otherSerialStream) = delete; 127 | 128 | /** 129 | * @brief Prevents copying of objects of this class by declaring the 130 | * assignment operator private. This method is never defined. 131 | */ 132 | SerialStream& operator=(const SerialStream& otherSerialStream) = delete; 133 | 134 | /** 135 | * @brief Move assignment is not allowed. 136 | */ 137 | SerialStream& operator=(const SerialStream&& otherSerialStream) = delete; 138 | 139 | /** 140 | * @brief Opens the serial port associated with the specified 141 | * file name and the specified mode. 142 | * @param fileName The file name of the serial port. 143 | * @param openMode The communication mode status when the serial 144 | * communication port is opened. 145 | * @param exclusive Set exclusive access for this process to the 146 | * serial port. 147 | */ 148 | void Open(const std::string& fileName, 149 | const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out, 150 | bool exclusive = true) ; 151 | 152 | /** 153 | * @brief Closes the serial port. All settings of the serial port will be 154 | * lost and no more I/O can be performed on the serial port. 155 | */ 156 | void Close() ; 157 | 158 | /** 159 | * @brief Waits until the write buffer is drained and then returns. 160 | */ 161 | void DrainWriteBuffer() ; 162 | 163 | /** 164 | * @brief Flushes the serial port input buffer. 165 | */ 166 | void FlushInputBuffer() ; 167 | 168 | /** 169 | * @brief Flushes the serial port output buffer. 170 | */ 171 | void FlushOutputBuffer() ; 172 | 173 | /** 174 | * @brief Flushes the serial port input and output buffers. 175 | */ 176 | void FlushIOBuffers() ; 177 | 178 | /** 179 | * @brief Checks if data is available at the input of the serial port. 180 | * @return Returns true iff data is available to read. 181 | */ 182 | bool IsDataAvailable() ; 183 | 184 | /** 185 | * @brief Determines if the serial port is open for I/O. 186 | * @return Returns true iff the serial port is open. 187 | */ 188 | bool IsOpen() ; 189 | 190 | /** 191 | * @brief Sets the baud rate for the serial port to the specified value 192 | * @param baudRate The baud rate to be set for the serial port. 193 | */ 194 | void SetBaudRate(const BaudRate& baudRate) ; 195 | 196 | /** 197 | * @brief Gets the current baud rate for the serial port. 198 | * @return Returns the baud rate. 199 | */ 200 | BaudRate GetBaudRate() ; 201 | 202 | /** 203 | * @brief Sets the character size for the serial port. 204 | * @param characterSize The character size to be set. 205 | */ 206 | void SetCharacterSize(const CharacterSize& characterSize) ; 207 | 208 | /** 209 | * @brief Gets the character size being used for serial communication. 210 | * @return Returns the current character size. 211 | */ 212 | CharacterSize GetCharacterSize() ; 213 | 214 | /** 215 | * @brief Sets flow control for the serial port. 216 | * @param flowControlType The flow control type to be set. 217 | */ 218 | void SetFlowControl(const FlowControl& flowControlType) ; 219 | 220 | /** 221 | * @brief Gets the current flow control setting. 222 | * @return Returns the flow control type of the serial port. 223 | */ 224 | FlowControl GetFlowControl() ; 225 | 226 | /** 227 | * @brief Sets the parity type for the serial port. 228 | * @param parityType The parity type to be set. 229 | */ 230 | void SetParity(const Parity& parityType) ; 231 | 232 | /** 233 | * @brief Gets the parity type for the serial port. 234 | * @return Returns the parity type. 235 | */ 236 | Parity GetParity() ; 237 | 238 | /** 239 | * @brief Sets the number of stop bits to be used with the serial port. 240 | * @param stopBits The number of stop bits to set. 241 | */ 242 | void SetStopBits(const StopBits& stopBits) ; 243 | 244 | /** 245 | * @brief Gets the number of stop bits currently being used by the serial 246 | * @return Returns the number of stop bits. 247 | */ 248 | StopBits GetStopBits() ; 249 | 250 | /** 251 | * @brief Sets the minimum number of characters for non-canonical reads. 252 | * @note See VMIN in man termios(3). 253 | * @param vmin the number of minimum characters to be set. 254 | */ 255 | void SetVMin(const short vmin) ; 256 | 257 | /** 258 | * @brief Gets the VMIN value for the device, which represents the 259 | * minimum number of characters for non-canonical reads. 260 | * @return Returns the minimum number of characters for 261 | * non-canonical reads. 262 | */ 263 | short GetVMin() ; 264 | 265 | /** 266 | * @brief Sets character buffer timeout for non-canonical reads in deciseconds. 267 | * @param vtime The timeout value in deciseconds to be set. 268 | * @return Returns the character buffer timeout for non-canonical reads in deciseconds. 269 | */ 270 | void SetVTime(const short vtime) ; 271 | 272 | /** 273 | * @brief Gets the current timeout value for non-canonical reads in deciseconds. 274 | * @return Returns the character buffer timeout for non-canonical reads in deciseconds. 275 | */ 276 | short GetVTime() ; 277 | 278 | /** 279 | * @brief Sets the DTR line to the specified value. 280 | * @param dtrState The line voltage state to be set, 281 | * (true = high, false = low). 282 | */ 283 | void SetDTR(const bool dtrState = true) ; 284 | 285 | /** 286 | * @brief Gets the status of the DTR line. 287 | * @return Returns true iff the status of the DTR line is high. 288 | */ 289 | bool GetDTR() ; 290 | 291 | /** 292 | * @brief Set the RTS line to the specified value. 293 | * @param rtsState The line voltage state to be set, 294 | * (true = high, false = low). 295 | */ 296 | void SetRTS(const bool rtsState = true) ; 297 | 298 | /** 299 | * @brief Get the status of the RTS line. 300 | * @return Returns true iff the status of the RTS line is high. 301 | */ 302 | bool GetRTS() ; 303 | 304 | /** 305 | * @brief Get the status of the CTS line. 306 | * @return Returns true iff the status of the CTS line is high. 307 | */ 308 | bool GetCTS() ; 309 | 310 | /** 311 | * @brief Get the status of the DSR line. 312 | * @return Returns true iff the status of the DSR line is high. 313 | */ 314 | bool GetDSR() ; 315 | 316 | /** 317 | * @brief Gets the serial port file descriptor. 318 | * @return Returns the serial port file descriptor. 319 | */ 320 | int GetFileDescriptor() ; 321 | 322 | /** 323 | * @brief Gets the number of bytes available in the read buffer. 324 | * @return Returns the number of bytes avilable in the read buffer. 325 | */ 326 | int GetNumberOfBytesAvailable() ; 327 | 328 | /** 329 | * @brief Gets a list of available serial ports. 330 | * @return Returns a std::vector of std::strings with the name of 331 | * each available serial port. 332 | * 333 | * @todo Consider making this a static member function. 334 | */ 335 | std::vector GetAvailableSerialPorts() ; 336 | 337 | 338 | protected: 339 | 340 | private: 341 | /** 342 | * @brief The SerialStreamBuffer object that will be used by the 343 | * stream to communicate with the serial port. 344 | */ 345 | std::unique_ptr mIOBuffer {nullptr} ; 346 | 347 | } ; // class SerialStream 348 | 349 | } // namespace LibSerial 350 | -------------------------------------------------------------------------------- /stamp-h.in: -------------------------------------------------------------------------------- 1 | timestamp 2 | -------------------------------------------------------------------------------- /sync_docs.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | rsync -avP doc/user_manual/_build/html/ libserial:/home/project-web/libserial/htdocs/ 3 | rsync -avP doc/html/ libserial:/home/project-web/libserial/htdocs/doxygen/ 4 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_EXECUTABLE(UnitTests 2 | SerialPortUnitTests.cpp 3 | SerialStreamUnitTests.cpp 4 | MultiThreadUnitTests.cpp 5 | UnitTests.cpp 6 | ) 7 | 8 | TARGET_LINK_LIBRARIES(UnitTests 9 | libserial_static 10 | GTestMain 11 | ) 12 | 13 | ADD_EXECUTABLE(unit_tests 14 | unit_tests.cpp 15 | ) 16 | 17 | TARGET_LINK_LIBRARIES(unit_tests 18 | libserial_static 19 | ${Boost_LIBRARIES} 20 | ) 21 | 22 | target_include_directories(UnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src) 23 | target_include_directories(unit_tests PRIVATE ${PROJECT_SOURCE_DIR}/src) 24 | 25 | 26 | ADD_TEST(NAME UnitTests COMMAND UnitTests) 27 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CXXFLAGS = -Weffc++ 2 | 3 | AM_CPPFLAGS = -I@top_srcdir@/src 4 | 5 | noinst_PROGRAMS = unit_tests UnitTests 6 | 7 | unit_tests_SOURCES = unit_tests.cpp 8 | 9 | unit_tests_LDADD = \ 10 | ../src/libserial.la \ 11 | -lboost_unit_test_framework 12 | 13 | noinst_HEADERS = \ 14 | SerialPortUnitTests.h \ 15 | SerialStreamUnitTests.h \ 16 | MultiThreadUnitTests.h \ 17 | UnitTests.h 18 | 19 | UnitTests_SOURCES = \ 20 | SerialPortUnitTests.cpp \ 21 | SerialStreamUnitTests.cpp \ 22 | MultiThreadUnitTests.cpp \ 23 | UnitTests.cpp 24 | 25 | UnitTests_LDADD = \ 26 | ../src/libserial.la \ 27 | -lgtest \ 28 | -lgtest_main \ 29 | -lpthread 30 | -------------------------------------------------------------------------------- /test/MultiThreadUnitTests.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file MultiThreadUnitTests.cpp * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #include "MultiThreadUnitTests.h" 35 | #include "UnitTests.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | using namespace LibSerial; 44 | 45 | MultiThreadUnitTests::MultiThreadUnitTests() 46 | { 47 | // Empty 48 | } 49 | 50 | MultiThreadUnitTests::~MultiThreadUnitTests() 51 | { 52 | // Empty 53 | } 54 | 55 | void 56 | MultiThreadUnitTests::serialStream1ThreadLoop() 57 | { 58 | size_t threadLoopStartTimeMilliseconds = getTimeInMilliSeconds() ; 59 | size_t timeElapsedMilliSeconds = 0; 60 | 61 | while (timeElapsedMilliSeconds < timeOutMilliseconds) 62 | { 63 | // 64 | // Write data to the serial port. It should be received by the other 65 | // thread. 66 | // 67 | serialStream1 << writeString1 << std::endl; 68 | serialStream1.DrainWriteBuffer() ; 69 | 70 | // 71 | // Wait for data to arrive from the other thread 72 | // 73 | if (serialStream1.IsDataAvailable()) 74 | { 75 | alarm(5) ; // Set a system alarm in case getline() blocks longer than 5 seconds. 76 | readString2.clear() ; 77 | getline(serialStream1, readString2) ; 78 | alarm(0) ; // Deactivate the alarm. 79 | 80 | if(readString2 != writeString2) 81 | { 82 | const std::lock_guard lock {mutex} ; 83 | failureRate++; 84 | } 85 | } 86 | 87 | const std::lock_guard lock {mutex} ; 88 | loopCount++; 89 | 90 | timeElapsedMilliSeconds = getTimeInMilliSeconds() - threadLoopStartTimeMilliseconds; 91 | } 92 | } 93 | 94 | void 95 | MultiThreadUnitTests::serialStream2ThreadLoop() 96 | { 97 | const size_t threadLoopStartTimeMilliseconds = getTimeInMilliSeconds() ; 98 | size_t timeElapsedMilliSeconds = 0; 99 | 100 | while (timeElapsedMilliSeconds < timeOutMilliseconds) 101 | { 102 | // 103 | // Write data to the serial port. It should be received by the other 104 | // thread. 105 | // 106 | serialStream2 << writeString2 << std::endl; 107 | serialStream2.DrainWriteBuffer() ; 108 | 109 | // 110 | // Wait for data to arrive from the other thread 111 | // 112 | if (serialStream2.IsDataAvailable()) 113 | { 114 | alarm(5) ; // Set a system alarm in case getline() blocks longer than 5 seconds. 115 | readString1.clear() ; 116 | getline(serialStream2, readString1) ; 117 | alarm(0) ; // Deactivate the alarm. 118 | 119 | if(readString1 != writeString1) 120 | { 121 | const std::lock_guard lock {mutex} ; 122 | failureRate++; 123 | } 124 | } 125 | 126 | const std::lock_guard lock {mutex} ; 127 | loopCount++; 128 | 129 | timeElapsedMilliSeconds = getTimeInMilliSeconds() - threadLoopStartTimeMilliseconds; 130 | } 131 | } 132 | 133 | void 134 | MultiThreadUnitTests::serialPort1ThreadLoop() 135 | { 136 | const size_t threadLoopStartTimeMilliseconds = getTimeInMilliSeconds() ; 137 | size_t timeElapsedMilliSeconds = 0; 138 | 139 | while (timeElapsedMilliSeconds < timeOutMilliseconds) 140 | { 141 | // 142 | // Write data to the serial port. It should be received by the other 143 | // thread. 144 | // 145 | serialPort1.Write(writeString1 + '\n') ; 146 | serialPort1.DrainWriteBuffer() ; 147 | 148 | // 149 | // Wait for data to arrive from the other thread 150 | // 151 | if (serialPort1.IsDataAvailable()) 152 | { 153 | try 154 | { 155 | readString2.clear() ; 156 | serialPort1.ReadLine(readString2, '\n', timeOutMilliseconds) ; 157 | } 158 | catch (const std::exception& err) 159 | { 160 | std::cerr << err.what() << std::endl ; 161 | } 162 | 163 | if(readString2 != writeString2 + '\n') 164 | { 165 | const std::lock_guard lock {mutex} ; 166 | failureRate++; 167 | } 168 | } 169 | 170 | const std::lock_guard lock {mutex} ; 171 | loopCount++; 172 | 173 | timeElapsedMilliSeconds = getTimeInMilliSeconds() - threadLoopStartTimeMilliseconds; 174 | } 175 | } 176 | 177 | void 178 | MultiThreadUnitTests::serialPort2ThreadLoop() 179 | { 180 | const size_t threadLoopStartTimeMilliseconds = getTimeInMilliSeconds() ; 181 | size_t timeElapsedMilliSeconds = 0; 182 | 183 | while (timeElapsedMilliSeconds < timeOutMilliseconds) 184 | { 185 | // 186 | // Write data to the serial port. It should be received by the other 187 | // thread. 188 | // 189 | serialPort2.Write(writeString2 + '\n') ; 190 | serialPort2.DrainWriteBuffer() ; 191 | 192 | // 193 | // Wait for data to arrive from the other thread 194 | // 195 | if (serialPort2.IsDataAvailable()) 196 | { 197 | try 198 | { 199 | readString1.clear() ; 200 | serialPort2.ReadLine(readString1, '\n', timeOutMilliseconds) ; 201 | } 202 | catch (const std::exception& err) 203 | { 204 | std::cerr << err.what() << std::endl ; 205 | } 206 | 207 | if(readString1 != writeString1 + '\n') 208 | { 209 | const std::lock_guard lock {mutex} ; 210 | failureRate++; 211 | } 212 | } 213 | 214 | const std::lock_guard lock {mutex} ; 215 | loopCount++; 216 | 217 | timeElapsedMilliSeconds = getTimeInMilliSeconds() - threadLoopStartTimeMilliseconds; 218 | } 219 | } 220 | 221 | void 222 | MultiThreadUnitTests::testMultiThreadSerialStreamReadWrite() 223 | { 224 | // 225 | // We must open the two serial ports before spawning the threads. 226 | // Otherwise, one thread may flush the serial port I/O buffers *after* the 227 | // other thread has already sent data. 228 | // 229 | serialStream1.Open(SERIAL_PORT_1) ; 230 | serialStream1.SetBaudRate(BaudRate::BAUD_115200) ; 231 | serialStream1.SetFlowControl(FlowControl::FLOW_CONTROL_HARDWARE) ; 232 | 233 | serialStream2.Open(SERIAL_PORT_2) ; 234 | serialStream2.SetBaudRate(BaudRate::BAUD_115200) ; 235 | serialStream2.SetFlowControl(FlowControl::FLOW_CONTROL_HARDWARE) ; 236 | 237 | std::thread serialStream1Thread(&MultiThreadUnitTests::serialStream1ThreadLoop, this) ; 238 | std::thread serialStream2Thread(&MultiThreadUnitTests::serialStream2ThreadLoop, this) ; 239 | 240 | serialStream1Thread.join() ; 241 | serialStream2Thread.join() ; 242 | 243 | serialStream1.Close() ; 244 | serialStream2.Close() ; 245 | } 246 | 247 | void 248 | MultiThreadUnitTests::testMultiThreadSerialPortReadWrite() 249 | { 250 | // 251 | // We must open the two serial ports before spawning the threads. 252 | // Otherwise, one thread may flush the serial port I/O buffers *after* the 253 | // other thread has already sent data. 254 | // 255 | serialPort1.Open(SERIAL_PORT_1) ; 256 | serialPort1.SetBaudRate(BaudRate::BAUD_115200) ; 257 | serialPort1.SetFlowControl(FlowControl::FLOW_CONTROL_HARDWARE) ; 258 | 259 | serialPort2.Open(SERIAL_PORT_2) ; 260 | serialPort2.SetBaudRate(BaudRate::BAUD_115200) ; 261 | serialPort2.SetFlowControl(FlowControl::FLOW_CONTROL_HARDWARE) ; 262 | 263 | std::thread serialPort1Thread(&MultiThreadUnitTests::serialPort1ThreadLoop, this) ; 264 | std::thread serialPort2Thread(&MultiThreadUnitTests::serialPort2ThreadLoop, this) ; 265 | 266 | serialPort1Thread.join() ; 267 | serialPort2Thread.join() ; 268 | 269 | serialPort1.Close() ; 270 | serialPort2.Close() ; 271 | } 272 | 273 | TEST_F(MultiThreadUnitTests, testMultiThreadSerialStreamReadWrite) 274 | { 275 | SCOPED_TRACE("Test Multi-Thread Serial Stream Communication.") ; 276 | 277 | failureRate = 0 ; 278 | loopCount = 0 ; 279 | 280 | for (size_t i = 0; i < TEST_ITERATIONS; i++) 281 | { 282 | testMultiThreadSerialStreamReadWrite() ; 283 | } 284 | 285 | const auto failRate = ( 286 | 100. * static_cast(failureRate) / 287 | static_cast(loopCount) 288 | ) ; 289 | 290 | // If the serial communication fail rate is greater than 0.0001% consider it a failed test. 291 | if (failRate > 0.0001) 292 | { 293 | std::cout << "\t SerialStream Failure Rate = " << failRate << "%" << std::endl; 294 | ADD_FAILURE() ; 295 | } 296 | } 297 | 298 | TEST_F(MultiThreadUnitTests, testMultiThreadSerialPortReadWrite) 299 | { 300 | SCOPED_TRACE("Test Multi-Thread Serial Port Communication.") ; 301 | 302 | failureRate = 0; 303 | loopCount = 0; 304 | 305 | for (size_t i = 0; i < TEST_ITERATIONS; i++) 306 | { 307 | testMultiThreadSerialPortReadWrite() ; 308 | } 309 | 310 | const auto failRate = ( 311 | 100. * static_cast(failureRate) / 312 | static_cast(loopCount) 313 | ) ; 314 | 315 | // If the serial communication fail rate is greater than 0.0001% consider it a failed test. 316 | if (failRate > 0.0001) 317 | { 318 | std::cout << "\t SerialPort Failure Rate = " << failRate << "%" << std::endl; 319 | ADD_FAILURE() ; 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /test/MultiThreadUnitTests.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file SerialPortTests.h * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #pragma once 35 | 36 | #include "libserial/SerialPort.h" 37 | #include "libserial/SerialPortConstants.h" 38 | #include "UnitTests.h" 39 | 40 | #include 41 | #include 42 | 43 | /** 44 | * @namespace Libserial 45 | */ 46 | namespace LibSerial 47 | { 48 | class MultiThreadUnitTests : public UnitTests 49 | { 50 | public: 51 | 52 | /** 53 | * @brief Default Constructor. 54 | */ 55 | explicit MultiThreadUnitTests() ; 56 | 57 | /** 58 | * @brief Default Destructor. 59 | */ 60 | virtual ~MultiThreadUnitTests() ; 61 | 62 | protected: 63 | 64 | /** 65 | * @brief Tests for correct functionality of a multi-threaded serial stream application. 66 | */ 67 | void serialStream1ThreadLoop() ; 68 | 69 | /** 70 | * @brief Tests for correct functionality of a multi-threaded serial port application. 71 | */ 72 | void serialStream2ThreadLoop() ; 73 | 74 | /** 75 | * @brief Main loop for the multi-threaded serial stream unit test. 76 | */ 77 | void serialPort1ThreadLoop() ; 78 | 79 | /** 80 | * @brief Main loop for the multi-threaded serial port unit test. 81 | */ 82 | void serialPort2ThreadLoop() ; 83 | 84 | /** 85 | * @brief Entry point for the multi-thread serial stream unit test. 86 | */ 87 | void testMultiThreadSerialStreamReadWrite() ; 88 | 89 | /** 90 | * @brief Entry point for the multi-thread serial port unit test. 91 | */ 92 | void testMultiThreadSerialPortReadWrite() ; 93 | 94 | /** 95 | * @param C++11 thread std::mutex for locking parameters in the threaded unit tests. 96 | */ 97 | std::mutex mutex {} ; 98 | 99 | } ; // class MultiThreadUnitTests 100 | 101 | } // namespace LibSerial 102 | -------------------------------------------------------------------------------- /test/SerialPortUnitTests.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file SerialPortUnitTests.h * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #pragma once 35 | 36 | #include "UnitTests.h" 37 | #include "libserial/SerialPort.h" 38 | #include "libserial/SerialPortConstants.h" 39 | 40 | #include 41 | #include 42 | 43 | /** 44 | * @namespace Libserial 45 | */ 46 | namespace LibSerial 47 | { 48 | class SerialPortUnitTests : public UnitTests 49 | { 50 | public: 51 | 52 | /** 53 | * @brief Default Constructor. 54 | */ 55 | explicit SerialPortUnitTests() ; 56 | 57 | /** 58 | * @brief Default Destructor. 59 | */ 60 | virtual ~SerialPortUnitTests() ; 61 | 62 | protected: 63 | 64 | /** 65 | * @brief Tests constructor overloads and destructors. 66 | */ 67 | void testSerialPortConstructors() ; 68 | 69 | /** 70 | * @brief Test move construction of SerialPort instances. 71 | */ 72 | void testSerialPortMoveConstruction() ; 73 | 74 | /** 75 | * @brief Test move assignment of SerialPort instances. 76 | */ 77 | void testSerialPortMoveAssignment() ; 78 | 79 | /** 80 | * @brief Tests correct functionality for opening and closing serial ports. 81 | */ 82 | void testSerialPortOpenClose() ; 83 | 84 | /** 85 | * @brief Tests correct functionality for draining the hardware write buffer using tcdrain(). 86 | */ 87 | void testSerialPortDrainWriteBuffer() ; 88 | 89 | /** 90 | * @brief Tests correct functionality for draining the hardware input (read) buffer using tcflush() ; 91 | */ 92 | void testSerialPortFlushInputBuffer() ; 93 | 94 | /** 95 | * @brief Tests correct functionality for draining the hardware write buffer using tcflush() ; 96 | */ 97 | void testSerialPortFlushOutputBuffer() ; 98 | 99 | /** 100 | * @brief Tests correct functionality for draining the hardware read/write buffers using tcflush() ; 101 | */ 102 | void testSerialPortFlushIOBuffers() ; 103 | 104 | /** 105 | * @brief Tests correct functionality for checking if data is available. 106 | */ 107 | void testSerialPortIsDataAvailableTest() ; 108 | 109 | /** 110 | * @brief Tests for correct functionality of the Open() and Close() methods. 111 | */ 112 | void testSerialPortIsOpenTest() ; 113 | 114 | /** 115 | * @brief Tests for correct functionality of the SetBaudRate() and GetBaudRate() methods. 116 | */ 117 | void testSerialPortSetGetBaudRate() ; 118 | 119 | /** 120 | * @brief Tests for correct functionality of the SetCharacterSize() and GetCharactersize() methods. 121 | */ 122 | void testSerialPortSetGetCharacterSize() ; 123 | 124 | /** 125 | * @brief Tests for correct functionality of the SetFlowControl() and GetFlowControl() methods. 126 | */ 127 | void testSerialPortSetGetFlowControl() ; 128 | 129 | /** 130 | * @brief Tests for correct functionality of the SetParity() and GetParity() methods. 131 | */ 132 | void testSerialPortSetGetParity() ; 133 | 134 | /** 135 | * @brief Tests for correct functionality of the SetStopBits() and GetStopBits() methods. 136 | */ 137 | void testSerialPortSetGetStopBits() ; 138 | 139 | /** 140 | * @brief Tests for correct functionality of the SetVMin() and GetVMin() methods. 141 | */ 142 | void testSerialPortSetGetVMin() ; 143 | 144 | /** 145 | * @brief Tests for correct functionality of the SetVTime() and GetVMin() methods. 146 | */ 147 | void testSerialPortSetGetVTime() ; 148 | 149 | /** 150 | * @brief Tests for correct functionality of the SetDTR() and GetDTR() methods. 151 | */ 152 | void testSerialPortSetGetDTR() ; 153 | 154 | /** 155 | * @brief Tests for correct functionality of the SetRTS() and GetRTS() methods. 156 | */ 157 | void testSerialPortSetGetRTS() ; 158 | 159 | /** 160 | * @brief Tests for correct functionality of the SetRTS() and GetCTS() methods. 161 | */ 162 | void testSerialPortSetRTSGetCTS() ; 163 | 164 | /** 165 | * @brief Tests for correct functionality of the SetDTR() and GetDSR() methods. 166 | */ 167 | void testSerialPortSetDTRGetDSR() ; 168 | 169 | /** 170 | * @brief Tests for correct functionality of the GetFileDescriptor() method. 171 | */ 172 | void testSerialPortGetFileDescriptor() ; 173 | 174 | /** 175 | * @brief Tests for correct functionality of the GetNumberOfBytesAvailable() method. 176 | */ 177 | void testSerialPortGetNumberOfBytesAvailable() ; 178 | 179 | #ifdef __linux__ 180 | /** 181 | * @brief Tests for correct functionality of the GetAvailableSerialPorts() method. 182 | */ 183 | void testSerialPortGetAvailableSerialPorts() ; 184 | #endif 185 | 186 | /** 187 | * @brief Tests for correct functionality of the ReadDataBuffer() and WriteDataBuffer() methods. 188 | */ 189 | void testSerialPortReadDataBufferWriteDataBuffer() ; 190 | 191 | /** 192 | * @brief Tests for correct functionality of the ReadString() and WriteString() methods. 193 | */ 194 | void testSerialPortReadStringWriteString() ; 195 | 196 | /** 197 | * @brief Tests for correct functionality of the ReadByte() and WriteByte() methods. 198 | */ 199 | void testSerialPortReadByteWriteByte() ; 200 | 201 | /** 202 | * @brief Tests for correct functionality of the ReadLine() and WriteString() methods. 203 | */ 204 | void testSerialPortReadLineWriteString() ; 205 | 206 | } ; // class SerialPortUnitTests 207 | 208 | } // namespace LibSerial 209 | -------------------------------------------------------------------------------- /test/SerialStreamUnitTests.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file SerialStreamUnitTests.h * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #pragma once 35 | 36 | #include "UnitTests.h" 37 | #include "libserial/SerialPort.h" 38 | #include "libserial/SerialPortConstants.h" 39 | #include "libserial/SerialStream.h" 40 | 41 | #include 42 | #include 43 | 44 | /** 45 | * @namespace Libserial 46 | */ 47 | namespace LibSerial 48 | { 49 | class SerialStreamUnitTests : public UnitTests 50 | { 51 | public: 52 | 53 | /** 54 | * @brief Default Constructor. 55 | */ 56 | explicit SerialStreamUnitTests() ; 57 | 58 | /** 59 | * @brief Default Destructor. 60 | */ 61 | virtual ~SerialStreamUnitTests() ; 62 | 63 | protected: 64 | 65 | /** 66 | * @brief Tests constructor overloads and destructors. 67 | */ 68 | void testSerialStreamConstructors() ; 69 | 70 | /** 71 | * @brief Tests correct functionality for opening and closing serial streams. 72 | */ 73 | void testSerialStreamOpenClose() ; 74 | 75 | /** 76 | * @brief Tests correct functionality for draining the hardware write buffer using tcdrain(). 77 | */ 78 | void testSerialStreamDrainWriteBuffer() ; 79 | 80 | /** 81 | * @brief Tests correct functionality for draining the hardware input (read) buffer using tcflush() ; 82 | */ 83 | void testSerialStreamFlushInputBuffer() ; 84 | 85 | /** 86 | * @brief Tests correct functionality for draining the hardware write buffer using tcflush() ; 87 | */ 88 | void testSerialStreamFlushOutputBuffer() ; 89 | 90 | /** 91 | * @brief Tests correct functionality for draining the hardware read/write buffers using tcflush() ; 92 | */ 93 | void testSerialStreamFlushIOBuffers() ; 94 | 95 | /** 96 | * @brief Tests correct functionality for checking if data is available. 97 | */ 98 | void testSerialStreamIsDataAvailableTest() ; 99 | 100 | /** 101 | * @brief Tests for correct functionality of the Open() and Close() methods. 102 | */ 103 | void testSerialStreamIsOpenTest() ; 104 | 105 | /** 106 | * @brief Tests for correct functionality of the SetBaudRate() and GetBaudRate() methods. 107 | */ 108 | void testSerialStreamSetGetBaudRate() ; 109 | 110 | /** 111 | * @brief Tests for correct functionality of the SetCharacterSize() and GetCharactersize() methods. 112 | */ 113 | void testSerialStreamSetGetCharacterSize() ; 114 | 115 | /** 116 | * @brief Tests for correct functionality of the SetFlowControl() and GetFlowControl() methods. 117 | */ 118 | void testSerialStreamSetGetFlowControl() ; 119 | 120 | /** 121 | * @brief Tests for correct functionality of the SetParity() and GetParity() methods. 122 | */ 123 | void testSerialStreamSetGetParity() ; 124 | 125 | /** 126 | * @brief Tests for correct functionality of the SetStopBits() and GetStopBits() methods. 127 | */ 128 | void testSerialStreamSetGetStopBits() ; 129 | 130 | /** 131 | * @brief Tests for correct functionality of the SetVMin() and GetVMin() methods. 132 | */ 133 | void testSerialStreamSetGetVMin() ; 134 | 135 | /** 136 | * @brief Tests for correct functionality of the SetVTime() and GetVMin() methods. 137 | */ 138 | void testSerialStreamSetGetVTime() ; 139 | 140 | /** 141 | * @brief Tests for correct functionality of the SetDTR() and GetDTR() methods. 142 | */ 143 | void testSerialStreamSetGetDTR() ; 144 | 145 | /** 146 | * @brief Tests for correct functionality of the SetRTS() and GetRTS() methods. 147 | */ 148 | void testSerialStreamSetGetRTS() ; 149 | 150 | /** 151 | * @brief Tests for correct functionality of the SetRTS() and GetCTS() methods. 152 | */ 153 | void testSerialStreamSetRTSGetCTS() ; 154 | 155 | /** 156 | * @brief Tests for correct functionality of the SetDTR() and GetDSR() methods. 157 | */ 158 | void testSerialStreamSetDTRGetDSR() ; 159 | 160 | /** 161 | * @brief Tests for correct functionality of the GetFileDescriptor() method. 162 | */ 163 | void testSerialStreamGetFileDescriptor() ; 164 | 165 | /** 166 | * @brief Tests for correct functionality of the GetNumberOfBytesAvailable() method. 167 | */ 168 | void testSerialStreamGetNumberOfBytesAvailable() ; 169 | 170 | #ifdef __linux__ 171 | /** 172 | * @brief Tests for correct functionality of the GetAvailableSerialPorts() method. 173 | */ 174 | void testSerialStreamGetAvailableSerialPorts() ; 175 | #endif 176 | 177 | /** 178 | * @brief Tests for correct functionality of the ReadByte() and WriteByte() methods. 179 | */ 180 | void testSerialStreamReadByteWriteByte() ; 181 | 182 | /** 183 | * @brief Tests for correct functionality of the GetLine() and WriteString() methods. 184 | */ 185 | void testSerialStreamGetLineWriteString() ; 186 | 187 | /** 188 | * @brief Tests for correct functionality of the Get() and WriteByte() methods. 189 | */ 190 | void testSerialStreamGetWriteByte() ; 191 | 192 | } ; // class SerialStreamUnitTests 193 | 194 | } // namespace LibSerial 195 | -------------------------------------------------------------------------------- /test/UnitTests.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file UnitTests.cpp * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #include "UnitTests.h" 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | using namespace LibSerial; 43 | 44 | UnitTests::UnitTests() 45 | { 46 | // Empty 47 | } 48 | 49 | 50 | UnitTests::~UnitTests() 51 | { 52 | // Empty 53 | } 54 | 55 | size_t 56 | UnitTests::getTimeInMilliSeconds() 57 | { 58 | std::chrono::high_resolution_clock::duration timeNow = 59 | std::chrono::high_resolution_clock::now().time_since_epoch() ; 60 | 61 | return static_cast( 62 | std::chrono::duration_cast(timeNow).count() 63 | ) ; 64 | } 65 | 66 | size_t 67 | UnitTests::getTimeInMicroSeconds() 68 | { 69 | std::chrono::high_resolution_clock::duration timeNow = 70 | std::chrono::high_resolution_clock::now().time_since_epoch() ; 71 | 72 | return static_cast( 73 | std::chrono::duration_cast(timeNow).count() 74 | ) ; 75 | } 76 | 77 | void 78 | UnitTests::testSerialStreamToSerialPortReadWrite() 79 | { 80 | serialPort1.Open(SERIAL_PORT_1) ; 81 | ASSERT_TRUE(serialPort1.IsOpen()) ; 82 | 83 | serialStream1.Open(SERIAL_PORT_2) ; 84 | ASSERT_TRUE(serialStream1.IsOpen()) ; 85 | 86 | const auto baud_rate = BaudRate::BAUD_115200 ; 87 | serialPort1.SetBaudRate(baud_rate) ; 88 | serialStream1.SetBaudRate(baud_rate) ; 89 | 90 | const auto baudRate1 = serialPort1.GetBaudRate() ; 91 | const auto baudRate2 = serialStream1.GetBaudRate() ; 92 | 93 | ASSERT_EQ(baudRate1, baud_rate) ; 94 | ASSERT_EQ(baudRate2, baud_rate) ; 95 | 96 | serialStream1 << writeString1 << std::endl; 97 | serialPort1.ReadLine(readString1, '\n', timeOutMilliseconds) ; 98 | 99 | ASSERT_EQ(readString1, writeString1 + '\n') ; 100 | ASSERT_EQ(readString1.size(), writeString1.size() + 1) ; 101 | 102 | serialPort1.Write(writeString2 + '\n') ; 103 | serialPort1.DrainWriteBuffer() ; 104 | getline(serialStream1, readString2) ; 105 | 106 | ASSERT_EQ(readString2, writeString2) ; 107 | 108 | serialPort1.Close() ; 109 | serialStream1.Close() ; 110 | 111 | ASSERT_FALSE(serialPort1.IsOpen()) ; 112 | ASSERT_FALSE(serialStream1.IsOpen()) ; 113 | } 114 | 115 | TEST_F(UnitTests, testSerialStreamToSerialPortReadWrite) 116 | { 117 | SCOPED_TRACE("Serial Stream To Serial Port Read and Write Test") ; 118 | 119 | for (size_t i = 0; i < TEST_ITERATIONS; i++) 120 | { 121 | testSerialStreamToSerialPortReadWrite() ; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /test/UnitTests.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file UnitTests.h * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #pragma once 35 | 36 | #include "libserial/SerialPort.h" 37 | #include "libserial/SerialPortConstants.h" 38 | #include "libserial/SerialStream.h" 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | /** 46 | * @namespace Libserial 47 | */ 48 | namespace LibSerial 49 | { 50 | /** 51 | * @var Default Serial Port 1. 52 | */ 53 | constexpr const char* const SERIAL_PORT_1 = "/dev/ttyUSB0" ; 54 | 55 | /** 56 | * @var Default Serial Port 2. 57 | */ 58 | constexpr const char* const SERIAL_PORT_2 = "/dev/ttyUSB1" ; 59 | 60 | /** 61 | * @var The number of iterations to perform on each unit test. 62 | */ 63 | constexpr int TEST_ITERATIONS = 10 ; 64 | 65 | 66 | class UnitTests : public ::testing::Test 67 | { 68 | public: 69 | 70 | /** 71 | * @brief Default Constructor. 72 | */ 73 | explicit UnitTests() ; 74 | 75 | /** 76 | * @brief Default Destructor. 77 | */ 78 | virtual ~UnitTests() ; 79 | 80 | /** 81 | * @brief Gets the time since epoch in milliseconds. 82 | * @return Returns the time since epoch in milliseconds 83 | */ 84 | size_t getTimeInMilliSeconds() ; 85 | 86 | /** 87 | * @brief Gets the time since epoch in microseconds. 88 | * @return Returns the time since epoch in microseconds 89 | */ 90 | size_t getTimeInMicroSeconds() ; 91 | 92 | protected: 93 | 94 | /** 95 | * @brief Tests for correct functionality for writing data from a serial stream object and reading that data from a serial port object.. 96 | */ 97 | void testSerialStreamToSerialPortReadWrite() ; 98 | 99 | /** 100 | * @var Failure rate of serial communications being tracked in the threaded tests. 101 | */ 102 | size_t failureRate = 0 ; 103 | 104 | /** 105 | * @var Loop count variable. 106 | */ 107 | size_t loopCount = 0 ; 108 | 109 | /** 110 | * @var Timeout to be used for test methods, (ms). 111 | */ 112 | size_t timeOutMilliseconds = 250 ; 113 | 114 | /** 115 | * @var Time to allow the hardware read buffer to fill or empty (us). 116 | */ 117 | unsigned int readBufferDelay = 20000 ; 118 | 119 | /** 120 | * @struct Standard baud rates. 121 | */ 122 | std::vector baudRates {} ; 123 | 124 | /** 125 | * @struct Standard character sizes. 126 | */ 127 | std::vector characterSizes {} ; 128 | 129 | /** 130 | * @struct Standard flow control types. 131 | */ 132 | std::vector flowControlTypes {} ; 133 | 134 | /** 135 | * @struct Standard flow parity types. 136 | */ 137 | std::vector parityTypes {} ; 138 | 139 | /** 140 | * @struct Standard number of stop bits. 141 | */ 142 | std::vector stopBits {} ; 143 | 144 | /** 145 | * @param Serial Stream instance 1 for unit testing applications. 146 | */ 147 | LibSerial::SerialStream serialStream1 {} ; 148 | 149 | /** 150 | * @param Serial Stream instance 2 for unit testing applications. 151 | */ 152 | LibSerial::SerialStream serialStream2 {} ; 153 | 154 | /** 155 | * @param Serial Port instance 1 for unit testing applications. 156 | */ 157 | LibSerial::SerialPort serialPort1 {} ; 158 | 159 | /** 160 | * @param Serial Port instance 2 for unit testing applications. 161 | */ 162 | LibSerial::SerialPort serialPort2 {} ; 163 | 164 | /** 165 | * @param String to store received data. 166 | */ 167 | std::string readString1 {} ; 168 | 169 | /** 170 | * @param String to store received data. 171 | */ 172 | std::string readString2 {} ; 173 | 174 | /** 175 | * @param String to store data to be written to the serial port. 176 | */ 177 | std::string writeString1 {"Quidquid latine dictum sit, altum sonatur. (Whatever is said in Latin sounds profound.)"} ; 178 | 179 | /** 180 | * @param String to store data to be written to the serial port. 181 | */ 182 | std::string writeString2 {"The secret of the man who is universally interesting is that he is universally interested. - William Dean Howells"} ; 183 | 184 | private: 185 | 186 | } ; 187 | } 188 | -------------------------------------------------------------------------------- /test/unit_tests.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file unit_tests.cpp * 3 | * @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. * 4 | * crayzeewulf@gmail.com * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions * 8 | * are met: * 9 | * * 10 | * 1. Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * 2. Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * 3. Neither the name PX4 nor the names of its contributors may be * 17 | * used to endorse or promote products derived from this software * 18 | * without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * 30 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * 31 | * POSSIBILITY OF SUCH DAMAGE. * 32 | *****************************************************************************/ 33 | 34 | #include 35 | #include 36 | 37 | #define BOOST_TEST_MODULE libserial 38 | #define BOOST_TEST_DYN_LINK 39 | #define BOOST_TEST_MAIN 40 | #include 41 | 42 | BOOST_AUTO_TEST_CASE( SerialStreamBuf_Constructor_Test ) // NOLINT (cert-err58-cpp) 43 | { 44 | // 45 | // SerialStreamBuf should not be open on default construction 46 | // 47 | using LibSerial::SerialStreamBuf ; 48 | SerialStreamBuf buf ; 49 | BOOST_CHECK( false == buf.IsOpen() ) ; // NOLINT (cppcoreguidelines-pro-type-vararg) 50 | } 51 | 52 | BOOST_AUTO_TEST_CASE( SerialStream_Constructor_Test ) // NOLINT (cert-err58-cpp) 53 | { 54 | using LibSerial::SerialStream ; 55 | // 56 | // SerialStream should not be open on default construction 57 | // 58 | { 59 | SerialStream serial_stream; 60 | BOOST_CHECK( false == serial_stream.IsOpen() ) ; // NOLINT (cppcoreguidelines-pro-type-vararg) 61 | } 62 | // 63 | // Attempting to open a non-existent serial port should leave the 64 | // serial stream in non-good state. 65 | // 66 | { 67 | SerialStream serial_stream ; 68 | // NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg) 69 | BOOST_CHECK_THROW( 70 | serial_stream.Open("/dev/some_non_existent_device_hope_it_does_not_exist"), 71 | LibSerial::OpenFailed 72 | ) ; 73 | // NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg) 74 | BOOST_CHECK(not serial_stream.good()) ; 75 | } 76 | } 77 | 78 | --------------------------------------------------------------------------------