From cb2cc5c25964bc29fa17be7b361f46afc63fa8a0 Mon Sep 17 00:00:00 2001 From: "T. van der Zwan" Date: Tue, 5 Nov 2013 15:46:17 +0000 Subject: [PATCH] Removed incorrect file-headers Added rs232 library Added abstract Rs232 device Former-commit-id: 9a2830f71376f0716edea594afc526018a530fa3 --- dependencies/CMakeLists.txt | 7 - dependencies/build/CMakeLists.txt | 8 +- .../build/getoptPlusPlus/CMakeLists.txt | 8 - dependencies/build/jsoncpp/CMakeLists.txt | 8 - dependencies/include/serial/impl/unix.h | 204 +++++ dependencies/include/serial/impl/win.h | 201 +++++ dependencies/include/serial/serial.h | 700 ++++++++++++++++++ dependencies/include/serial/v8stdint.h | 57 ++ .../wjwwood-serial-master-20131105.zip | Bin 0 -> 58997 bytes libsrc/hyperion/CMakeLists.txt | 2 + libsrc/hyperion/LedRs232Device.cpp | 62 ++ libsrc/hyperion/LedRs232Device.h | 54 ++ libsrc/hyperion/LedSpiDevice.h | 22 +- 13 files changed, 1292 insertions(+), 41 deletions(-) create mode 100644 dependencies/include/serial/impl/unix.h create mode 100644 dependencies/include/serial/impl/win.h create mode 100644 dependencies/include/serial/serial.h create mode 100644 dependencies/include/serial/v8stdint.h create mode 100644 dependencies/wjwwood-serial-master-20131105.zip create mode 100644 libsrc/hyperion/LedRs232Device.cpp create mode 100644 libsrc/hyperion/LedRs232Device.h diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index a7d9a073..059e258e 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -1,9 +1,2 @@ -# Copyright (c) 2012 TNO, The Netherlands. -# -# This file contains information proprietary to TNO. -# -# Any disclosure or use of this information or any reproduction of this document or any part thereof for -# other than the specified purpose for which it is intended is expressly prohibited except as TNO may -# otherwise agree to in writing. add_subdirectory(build) diff --git a/dependencies/build/CMakeLists.txt b/dependencies/build/CMakeLists.txt index 00e5ed43..8edf5773 100644 --- a/dependencies/build/CMakeLists.txt +++ b/dependencies/build/CMakeLists.txt @@ -1,10 +1,4 @@ -# Copyright (c) 2012 TNO, The Netherlands. -# -# This file contains information proprietary to TNO. -# -# Any disclosure or use of this information or any reproduction of this document or any part thereof for -# other than the specified purpose for which it is intended is expressly prohibited except as TNO may -# otherwise agree to in writing. add_subdirectory(jsoncpp) add_subdirectory(getoptPlusPlus) +add_subdirectory(serial) diff --git a/dependencies/build/getoptPlusPlus/CMakeLists.txt b/dependencies/build/getoptPlusPlus/CMakeLists.txt index 3d471e22..e19880da 100644 --- a/dependencies/build/getoptPlusPlus/CMakeLists.txt +++ b/dependencies/build/getoptPlusPlus/CMakeLists.txt @@ -1,11 +1,3 @@ -# Copyright (c) 2012 TNO, The Netherlands. -# -# This file contains information proprietary to TNO. -# -# Any disclosure or use of this information or any reproduction of this document or any part thereof for -# other than the specified purpose for which it is intended is expressly prohibited except as TNO may -# otherwise agree to in writing. - project(getoptPlusPlus) include_directories( diff --git a/dependencies/build/jsoncpp/CMakeLists.txt b/dependencies/build/jsoncpp/CMakeLists.txt index 1b2f6197..8ebd71b7 100644 --- a/dependencies/build/jsoncpp/CMakeLists.txt +++ b/dependencies/build/jsoncpp/CMakeLists.txt @@ -1,11 +1,3 @@ -# Copyright (c) 2012 TNO, The Netherlands. -# -# This file contains information proprietary to TNO. -# -# Any disclosure or use of this information or any reproduction of this document or any part thereof for -# other than the specified purpose for which it is intended is expressly prohibited except as TNO may -# otherwise agree to in writing. - project(jsoncpp) # define the current source/header path diff --git a/dependencies/include/serial/impl/unix.h b/dependencies/include/serial/impl/unix.h new file mode 100644 index 00000000..a7985da3 --- /dev/null +++ b/dependencies/include/serial/impl/unix.h @@ -0,0 +1,204 @@ +/*! + * \file serial/impl/unix.h + * \author William Woodall + * \author John Harrison + * \version 0.1 + * + * \section LICENSE + * + * The MIT License + * + * Copyright (c) 2012 William Woodall, John Harrison + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * \section DESCRIPTION + * + * This provides a unix based pimpl for the Serial class. This implementation is + * based off termios.h and uses select for multiplexing the IO ports. + * + */ + +#if !defined(_WIN32) + +#ifndef SERIAL_IMPL_UNIX_H +#define SERIAL_IMPL_UNIX_H + +#include "serial/serial.h" + +#include + +namespace serial { + +using std::size_t; +using std::string; +using std::invalid_argument; + +using serial::SerialException; +using serial::IOException; + +class serial::Serial::SerialImpl { +public: + SerialImpl (const string &port, + unsigned long baudrate, + bytesize_t bytesize, + parity_t parity, + stopbits_t stopbits, + flowcontrol_t flowcontrol); + + virtual ~SerialImpl (); + + void + open (); + + void + close (); + + bool + isOpen () const; + + size_t + available (); + + size_t + read (uint8_t *buf, size_t size = 1); + + size_t + write (const uint8_t *data, size_t length); + + void + flush (); + + void + flushInput (); + + void + flushOutput (); + + void + sendBreak (int duration); + + void + setBreak (bool level); + + void + setRTS (bool level); + + void + setDTR (bool level); + + bool + waitForChange (); + + bool + getCTS (); + + bool + getDSR (); + + bool + getRI (); + + bool + getCD (); + + void + setPort (const string &port); + + string + getPort () const; + + void + setTimeout (Timeout &timeout); + + Timeout + getTimeout () const; + + void + setBaudrate (unsigned long baudrate); + + unsigned long + getBaudrate () const; + + void + setBytesize (bytesize_t bytesize); + + bytesize_t + getBytesize () const; + + void + setParity (parity_t parity); + + parity_t + getParity () const; + + void + setStopbits (stopbits_t stopbits); + + stopbits_t + getStopbits () const; + + void + setFlowcontrol (flowcontrol_t flowcontrol); + + flowcontrol_t + getFlowcontrol () const; + + void + readLock (); + + void + readUnlock (); + + void + writeLock (); + + void + writeUnlock (); + +protected: + void reconfigurePort (); + +private: + string port_; // Path to the file descriptor + int fd_; // The current file descriptor + + bool is_open_; + bool xonxoff_; + bool rtscts_; + + Timeout timeout_; // Timeout for read operations + unsigned long baudrate_; // Baudrate + + parity_t parity_; // Parity + bytesize_t bytesize_; // Size of the bytes + stopbits_t stopbits_; // Stop Bits + flowcontrol_t flowcontrol_; // Flow Control + + // Mutex used to lock the read functions + pthread_mutex_t read_mutex; + // Mutex used to lock the write functions + pthread_mutex_t write_mutex; +}; + +} + +#endif // SERIAL_IMPL_UNIX_H + +#endif // !defined(_WIN32) diff --git a/dependencies/include/serial/impl/win.h b/dependencies/include/serial/impl/win.h new file mode 100644 index 00000000..605f5d0f --- /dev/null +++ b/dependencies/include/serial/impl/win.h @@ -0,0 +1,201 @@ +/*! + * \file serial/impl/windows.h + * \author William Woodall + * \author John Harrison + * \version 0.1 + * + * \section LICENSE + * + * The MIT License + * + * Copyright (c) 2012 William Woodall, John Harrison + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * \section DESCRIPTION + * + * This provides a windows implementation of the Serial class interface. + * + */ + +#if defined(_WIN32) + +#ifndef SERIAL_IMPL_WINDOWS_H +#define SERIAL_IMPL_WINDOWS_H + +#include "serial/serial.h" + +#include "windows.h" + +namespace serial { + +using std::string; +using std::wstring; +using std::invalid_argument; + +using serial::SerialException; +using serial::IOException; + +class serial::Serial::SerialImpl { +public: + SerialImpl (const string &port, + unsigned long baudrate, + bytesize_t bytesize, + parity_t parity, + stopbits_t stopbits, + flowcontrol_t flowcontrol); + + virtual ~SerialImpl (); + + void + open (); + + void + close (); + + bool + isOpen () const; + + size_t + available (); + + size_t + read (uint8_t *buf, size_t size = 1); + + size_t + write (const uint8_t *data, size_t length); + + void + flush (); + + void + flushInput (); + + void + flushOutput (); + + void + sendBreak (int duration); + + void + setBreak (bool level); + + void + setRTS (bool level); + + void + setDTR (bool level); + + bool + waitForChange (); + + bool + getCTS (); + + bool + getDSR (); + + bool + getRI (); + + bool + getCD (); + + void + setPort (const string &port); + + string + getPort () const; + + void + setTimeout (Timeout &timeout); + + Timeout + getTimeout () const; + + void + setBaudrate (unsigned long baudrate); + + unsigned long + getBaudrate () const; + + void + setBytesize (bytesize_t bytesize); + + bytesize_t + getBytesize () const; + + void + setParity (parity_t parity); + + parity_t + getParity () const; + + void + setStopbits (stopbits_t stopbits); + + stopbits_t + getStopbits () const; + + void + setFlowcontrol (flowcontrol_t flowcontrol); + + flowcontrol_t + getFlowcontrol () const; + + void + readLock (); + + void + readUnlock (); + + void + writeLock (); + + void + writeUnlock (); + +protected: + void reconfigurePort (); + +private: + wstring port_; // Path to the file descriptor + HANDLE fd_; + + bool is_open_; + + Timeout timeout_; // Timeout for read operations + unsigned long baudrate_; // Baudrate + + parity_t parity_; // Parity + bytesize_t bytesize_; // Size of the bytes + stopbits_t stopbits_; // Stop Bits + flowcontrol_t flowcontrol_; // Flow Control + + // Mutex used to lock the read functions + HANDLE read_mutex; + // Mutex used to lock the write functions + HANDLE write_mutex; +}; + +} + +#endif // SERIAL_IMPL_WINDOWS_H + +#endif // if defined(_WIN32) diff --git a/dependencies/include/serial/serial.h b/dependencies/include/serial/serial.h new file mode 100644 index 00000000..0b3165a1 --- /dev/null +++ b/dependencies/include/serial/serial.h @@ -0,0 +1,700 @@ +/*! + * \file serial/serial.h + * \author William Woodall + * \author John Harrison + * \version 0.1 + * + * \section LICENSE + * + * The MIT License + * + * Copyright (c) 2012 William Woodall + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * \section DESCRIPTION + * + * This provides a cross platform interface for interacting with Serial Ports. + */ + +#ifndef SERIAL_H +#define SERIAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define THROW(exceptionClass, message) throw exceptionClass(__FILE__, \ +__LINE__, (message) ) + +namespace serial { + +/*! + * Enumeration defines the possible bytesizes for the serial port. + */ +typedef enum { + fivebits = 5, + sixbits = 6, + sevenbits = 7, + eightbits = 8 +} bytesize_t; + +/*! + * Enumeration defines the possible parity types for the serial port. + */ +typedef enum { + parity_none = 0, + parity_odd = 1, + parity_even = 2 +} parity_t; + +/*! + * Enumeration defines the possible stopbit types for the serial port. + */ +typedef enum { + stopbits_one = 1, + stopbits_two = 2, + stopbits_one_point_five +} stopbits_t; + +/*! + * Enumeration defines the possible flowcontrol types for the serial port. + */ +typedef enum { + flowcontrol_none = 0, + flowcontrol_software, + flowcontrol_hardware +} flowcontrol_t; + +/*! + * Structure for setting the timeout of the serial port, times are + * in milliseconds. + * + * In order to disable the interbyte timeout, set it to Timeout::max(). + */ +struct Timeout { +#ifdef max +# undef max +#endif + static uint32_t max() {return std::numeric_limits::max();} + /*! + * Convenience function to generate Timeout structs using a + * single absolute timeout. + * + * \param timeout A long that defines the time in milliseconds until a + * timeout occurs after a call to read or write is made. + * + * \return Timeout struct that represents this simple timeout provided. + */ + static Timeout simpleTimeout(uint32_t timeout) { + return Timeout(max(), timeout, 0, timeout, 0); + } + + /*! Number of milliseconds between bytes received to timeout on. */ + uint32_t inter_byte_timeout; + /*! A constant number of milliseconds to wait after calling read. */ + uint32_t read_timeout_constant; + /*! A multiplier against the number of requested bytes to wait after + * calling read. + */ + uint32_t read_timeout_multiplier; + /*! A constant number of milliseconds to wait after calling write. */ + uint32_t write_timeout_constant; + /*! A multiplier against the number of requested bytes to wait after + * calling write. + */ + uint32_t write_timeout_multiplier; + + explicit Timeout (uint32_t inter_byte_timeout_=0, + uint32_t read_timeout_constant_=0, + uint32_t read_timeout_multiplier_=0, + uint32_t write_timeout_constant_=0, + uint32_t write_timeout_multiplier_=0) + : inter_byte_timeout(inter_byte_timeout_), + read_timeout_constant(read_timeout_constant_), + read_timeout_multiplier(read_timeout_multiplier_), + write_timeout_constant(write_timeout_constant_), + write_timeout_multiplier(write_timeout_multiplier_) + {} +}; + +/*! + * Class that provides a portable serial port interface. + */ +class Serial { +public: + /*! + * Creates a Serial object and opens the port if a port is specified, + * otherwise it remains closed until serial::Serial::open is called. + * + * \param port A std::string containing the address of the serial port, + * which would be something like 'COM1' on Windows and '/dev/ttyS0' + * on Linux. + * + * \param baudrate An unsigned 32-bit integer that represents the baudrate + * + * \param timeout A serial::Timeout struct that defines the timeout + * conditions for the serial port. \see serial::Timeout + * + * \param bytesize Size of each byte in the serial transmission of data, + * default is eightbits, possible values are: fivebits, sixbits, sevenbits, + * eightbits + * + * \param parity Method of parity, default is parity_none, possible values + * are: parity_none, parity_odd, parity_even + * + * \param stopbits Number of stop bits used, default is stopbits_one, + * possible values are: stopbits_one, stopbits_one_point_five, stopbits_two + * + * \param flowcontrol Type of flowcontrol used, default is + * flowcontrol_none, possible values are: flowcontrol_none, + * flowcontrol_software, flowcontrol_hardware + * + * \throw serial::PortNotOpenedException + * \throw serial::IOException + * \throw std::invalid_argument + */ + Serial (const std::string &port = "", + uint32_t baudrate = 9600, + Timeout timeout = Timeout(), + bytesize_t bytesize = eightbits, + parity_t parity = parity_none, + stopbits_t stopbits = stopbits_one, + flowcontrol_t flowcontrol = flowcontrol_none); + + /*! Destructor */ + virtual ~Serial (); + + /*! + * Opens the serial port as long as the port is set and the port isn't + * already open. + * + * If the port is provided to the constructor then an explicit call to open + * is not needed. + * + * \see Serial::Serial + * + * \throw std::invalid_argument + * \throw serial::SerialException + * \throw serial::IOException + */ + void + open (); + + /*! Gets the open status of the serial port. + * + * \return Returns true if the port is open, false otherwise. + */ + bool + isOpen () const; + + /*! Closes the serial port. */ + void + close (); + + /*! Return the number of characters in the buffer. */ + size_t + available (); + + /*! Read a given amount of bytes from the serial port into a given buffer. + * + * The read function will return in one of three cases: + * * The number of requested bytes was read. + * * In this case the number of bytes requested will match the size_t + * returned by read. + * * A timeout occurred, in this case the number of bytes read will not + * match the amount requested, but no exception will be thrown. One of + * two possible timeouts occurred: + * * The inter byte timeout expired, this means that number of + * milliseconds elapsed between receiving bytes from the serial port + * exceeded the inter byte timeout. + * * The total timeout expired, which is calculated by multiplying the + * read timeout multiplier by the number of requested bytes and then + * added to the read timeout constant. If that total number of + * milliseconds elapses after the initial call to read a timeout will + * occur. + * * An exception occurred, in this case an actual exception will be thrown. + * + * \param buffer An uint8_t array of at least the requested size. + * \param size A size_t defining how many bytes to be read. + * + * \return A size_t representing the number of bytes read as a result of the + * call to read. + */ + size_t + read (uint8_t *buffer, size_t size); + + /*! Read a given amount of bytes from the serial port into a give buffer. + * + * \param buffer A reference to a std::vector of uint8_t. + * \param size A size_t defining how many bytes to be read. + * + * \return A size_t representing the number of bytes read as a result of the + * call to read. + */ + size_t + read (std::vector &buffer, size_t size = 1); + + /*! Read a given amount of bytes from the serial port into a give buffer. + * + * \param buffer A reference to a std::string. + * \param size A size_t defining how many bytes to be read. + * + * \return A size_t representing the number of bytes read as a result of the + * call to read. + */ + size_t + read (std::string &buffer, size_t size = 1); + + /*! Read a given amount of bytes from the serial port and return a string + * containing the data. + * + * \param size A size_t defining how many bytes to be read. + * + * \return A std::string containing the data read from the port. + */ + std::string + read (size_t size = 1); + + /*! Reads in a line or until a given delimiter has been processed. + * + * Reads from the serial port until a single line has been read. + * + * \param buffer A std::string reference used to store the data. + * \param size A maximum length of a line, defaults to 65536 (2^16) + * \param eol A string to match against for the EOL. + * + * \return A size_t representing the number of bytes read. + */ + size_t + readline (std::string &buffer, size_t size = 65536, std::string eol = "\n"); + + /*! Reads in a line or until a given delimiter has been processed. + * + * Reads from the serial port until a single line has been read. + * + * \param size A maximum length of a line, defaults to 65536 (2^16) + * \param eol A string to match against for the EOL. + * + * \return A std::string containing the line. + */ + std::string + readline (size_t size = 65536, std::string eol = "\n"); + + /*! Reads in multiple lines until the serial port times out. + * + * This requires a timeout > 0 before it can be run. It will read until a + * timeout occurs and return a list of strings. + * + * \param size A maximum length of combined lines, defaults to 65536 (2^16) + * + * \param eol A string to match against for the EOL. + * + * \return A vector containing the lines. + */ + std::vector + readlines (size_t size = 65536, std::string eol = "\n"); + + /*! Write a string to the serial port. + * + * \param data A const reference containing the data to be written + * to the serial port. + * + * \param size A size_t that indicates how many bytes should be written from + * the given data buffer. + * + * \return A size_t representing the number of bytes actually written to + * the serial port. + */ + size_t + write (const uint8_t *data, size_t size); + + /*! Write a string to the serial port. + * + * \param data A const reference containing the data to be written + * to the serial port. + * + * \return A size_t representing the number of bytes actually written to + * the serial port. + */ + size_t + write (const std::vector &data); + + /*! Write a string to the serial port. + * + * \param data A const reference containing the data to be written + * to the serial port. + * + * \return A size_t representing the number of bytes actually written to + * the serial port. + */ + size_t + write (const std::string &data); + + /*! Sets the serial port identifier. + * + * \param port A const std::string reference containing the address of the + * serial port, which would be something like 'COM1' on Windows and + * '/dev/ttyS0' on Linux. + * + * \throw InvalidConfigurationException + */ + void + setPort (const std::string &port); + + /*! Gets the serial port identifier. + * + * \see Serial::setPort + * + * \throw InvalidConfigurationException + */ + std::string + getPort () const; + + /*! Sets the timeout for reads and writes using the Timeout struct. + * + * There are two timeout conditions described here: + * * The inter byte timeout: + * * The inter_byte_timeout component of serial::Timeout defines the + * maximum amount of time, in milliseconds, between receiving bytes on + * the serial port that can pass before a timeout occurs. Setting this + * to zero will prevent inter byte timeouts from occurring. + * * Total time timeout: + * * The constant and multiplier component of this timeout condition, + * for both read and write, are defined in serial::Timeout. This + * timeout occurs if the total time since the read or write call was + * made exceeds the specified time in milliseconds. + * * The limit is defined by multiplying the multiplier component by the + * number of requested bytes and adding that product to the constant + * component. In this way if you want a read call, for example, to + * timeout after exactly one second regardless of the number of bytes + * you asked for then set the read_timeout_constant component of + * serial::Timeout to 1000 and the read_timeout_multiplier to zero. + * This timeout condition can be used in conjunction with the inter + * byte timeout condition with out any problems, timeout will simply + * occur when one of the two timeout conditions is met. This allows + * users to have maximum control over the trade-off between + * responsiveness and efficiency. + * + * Read and write functions will return in one of three cases. When the + * reading or writing is complete, when a timeout occurs, or when an + * exception occurs. + * + * \param timeout A serial::Timeout struct containing the inter byte + * timeout, and the read and write timeout constants and multipliers. + * + * \see serial::Timeout + */ + void + setTimeout (Timeout &timeout); + + /*! Sets the timeout for reads and writes. */ + void + setTimeout (uint32_t inter_byte_timeout, uint32_t read_timeout_constant, + uint32_t read_timeout_multiplier, uint32_t write_timeout_constant, + uint32_t write_timeout_multiplier) + { + Timeout timeout(inter_byte_timeout, read_timeout_constant, + read_timeout_multiplier, write_timeout_constant, + write_timeout_multiplier); + return setTimeout(timeout); + } + + /*! Gets the timeout for reads in seconds. + * + * \return A Timeout struct containing the inter_byte_timeout, and read + * and write timeout constants and multipliers. + * + * \see Serial::setTimeout + */ + Timeout + getTimeout () const; + + /*! Sets the baudrate for the serial port. + * + * Possible baudrates depends on the system but some safe baudrates include: + * 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000, + * 57600, 115200 + * Some other baudrates that are supported by some comports: + * 128000, 153600, 230400, 256000, 460800, 921600 + * + * \param baudrate An integer that sets the baud rate for the serial port. + * + * \throw InvalidConfigurationException + */ + void + setBaudrate (uint32_t baudrate); + + /*! Gets the baudrate for the serial port. + * + * \return An integer that sets the baud rate for the serial port. + * + * \see Serial::setBaudrate + * + * \throw InvalidConfigurationException + */ + uint32_t + getBaudrate () const; + + /*! Sets the bytesize for the serial port. + * + * \param bytesize Size of each byte in the serial transmission of data, + * default is eightbits, possible values are: fivebits, sixbits, sevenbits, + * eightbits + * + * \throw InvalidConfigurationException + */ + void + setBytesize (bytesize_t bytesize); + + /*! Gets the bytesize for the serial port. + * + * \see Serial::setBytesize + * + * \throw InvalidConfigurationException + */ + bytesize_t + getBytesize () const; + + /*! Sets the parity for the serial port. + * + * \param parity Method of parity, default is parity_none, possible values + * are: parity_none, parity_odd, parity_even + * + * \throw InvalidConfigurationException + */ + void + setParity (parity_t parity); + + /*! Gets the parity for the serial port. + * + * \see Serial::setParity + * + * \throw InvalidConfigurationException + */ + parity_t + getParity () const; + + /*! Sets the stopbits for the serial port. + * + * \param stopbits Number of stop bits used, default is stopbits_one, + * possible values are: stopbits_one, stopbits_one_point_five, stopbits_two + * + * \throw InvalidConfigurationException + */ + void + setStopbits (stopbits_t stopbits); + + /*! Gets the stopbits for the serial port. + * + * \see Serial::setStopbits + * + * \throw InvalidConfigurationException + */ + stopbits_t + getStopbits () const; + + /*! Sets the flow control for the serial port. + * + * \param flowcontrol Type of flowcontrol used, default is flowcontrol_none, + * possible values are: flowcontrol_none, flowcontrol_software, + * flowcontrol_hardware + * + * \throw InvalidConfigurationException + */ + void + setFlowcontrol (flowcontrol_t flowcontrol); + + /*! Gets the flow control for the serial port. + * + * \see Serial::setFlowcontrol + * + * \throw InvalidConfigurationException + */ + flowcontrol_t + getFlowcontrol () const; + + /*! Flush the input and output buffers */ + void + flush (); + + /*! Flush only the input buffer */ + void + flushInput (); + + /*! Flush only the output buffer */ + void + flushOutput (); + + /*! Sends the RS-232 break signal. See tcsendbreak(3). */ + void + sendBreak (int duration); + + /*! Set the break condition to a given level. Defaults to true. */ + void + setBreak (bool level = true); + + /*! Set the RTS handshaking line to the given level. Defaults to true. */ + void + setRTS (bool level = true); + + /*! Set the DTR handshaking line to the given level. Defaults to true. */ + void + setDTR (bool level = true); + + /*! + * Blocks until CTS, DSR, RI, CD changes or something interrupts it. + * + * Can throw an exception if an error occurs while waiting. + * You can check the status of CTS, DSR, RI, and CD once this returns. + * Uses TIOCMIWAIT via ioctl if available (mostly only on Linux) with a + * resolution of less than +-1ms and as good as +-0.2ms. Otherwise a + * polling method is used which can give +-2ms. + * + * \return Returns true if one of the lines changed, false if something else + * occurred. + * + * \throw SerialException + */ + bool + waitForChange (); + + /*! Returns the current status of the CTS line. */ + bool + getCTS (); + + /*! Returns the current status of the DSR line. */ + bool + getDSR (); + + /*! Returns the current status of the RI line. */ + bool + getRI (); + + /*! Returns the current status of the CD line. */ + bool + getCD (); + +private: + // Disable copy constructors + Serial(const Serial&); + Serial& operator=(const Serial&); + + std::string read_cache_; //!< Cache for doing reads in chunks. + + // Pimpl idiom, d_pointer + class SerialImpl; + SerialImpl *pimpl_; + + // Scoped Lock Classes + class ScopedReadLock; + class ScopedWriteLock; + + // Read common function + size_t + read_ (uint8_t *buffer, size_t size); + // Write common function + size_t + write_ (const uint8_t *data, size_t length); + +}; + +class SerialException : public std::exception +{ + // Disable copy constructors + SerialException& operator=(const SerialException&); + std::string e_what_; +public: + SerialException (const char *description) { + std::stringstream ss; + ss << "SerialException " << description << " failed."; + e_what_ = ss.str(); + } + SerialException (const SerialException& other) : e_what_(other.e_what_) {} + virtual ~SerialException() throw() {} + virtual const char* what () const throw () { + return e_what_.c_str(); + } +}; + +class IOException : public std::exception +{ + // Disable copy constructors + IOException& operator=(const IOException&); + std::string file_; + int line_; + std::string e_what_; + int errno_; +public: + explicit IOException (std::string file, int line, int errnum) + : file_(file), line_(line), errno_(errnum) { + std::stringstream ss; +#if defined(_WIN32) + char error_str [1024]; + strerror_s(error_str, 1024, errnum); +#else + char * error_str = strerror(errnum); +#endif + ss << "IO Exception (" << errno_ << "): " << error_str; + ss << ", file " << file_ << ", line " << line_ << "."; + e_what_ = ss.str(); + } + explicit IOException (std::string file, int line, const char * description) + : file_(file), line_(line), errno_(0) { + std::stringstream ss; + ss << "IO Exception: " << description; + ss << ", file " << file_ << ", line " << line_ << "."; + e_what_ = ss.str(); + } + virtual ~IOException() throw() {} + IOException (const IOException& other) : file_(other.file_), line_(other.line_), e_what_(other.e_what_), errno_(other.errno_) {} + + int getErrorNumber () { return errno_; } + + virtual const char* what () const throw () { + return e_what_.c_str(); + } +}; + +class PortNotOpenedException : public std::exception +{ + // Disable copy constructors + const PortNotOpenedException& operator=(PortNotOpenedException); + std::string e_what_; +public: + PortNotOpenedException (const char * description) { + std::stringstream ss; + ss << "PortNotOpenedException " << description << " failed."; + e_what_ = ss.str(); + } + PortNotOpenedException (const PortNotOpenedException& other) : e_what_(other.e_what_) {} + virtual ~PortNotOpenedException() throw() {} + virtual const char* what () const throw () { + return e_what_.c_str(); + } +}; + +} // namespace serial + +#endif diff --git a/dependencies/include/serial/v8stdint.h b/dependencies/include/serial/v8stdint.h new file mode 100644 index 00000000..f3be96b1 --- /dev/null +++ b/dependencies/include/serial/v8stdint.h @@ -0,0 +1,57 @@ +// This header is from the v8 google project: +// http://code.google.com/p/v8/source/browse/trunk/include/v8stdint.h + +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Load definitions of standard types. + +#ifndef V8STDINT_H_ +#define V8STDINT_H_ + +#include +#include + +#if defined(_WIN32) && !defined(__MINGW32__) + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; // NOLINT +typedef unsigned short uint16_t; // NOLINT +typedef int int32_t; +typedef unsigned int uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +// intptr_t and friends are defined in crtdefs.h through stdio.h. + +#else + +#include + +#endif + +#endif // V8STDINT_H_ diff --git a/dependencies/wjwwood-serial-master-20131105.zip b/dependencies/wjwwood-serial-master-20131105.zip new file mode 100644 index 0000000000000000000000000000000000000000..098d7f9c430826aeb880239ecdc3fa44faff4a9a GIT binary patch literal 58997 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 literal 0 HcmV?d00001 diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 8f52d048..b7449729 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -21,6 +21,7 @@ SET(Hyperion_HEADERS ${CURRENT_SOURCE_DIR}/BlackBorderProcessor.h ${CURRENT_SOURCE_DIR}/ImageToLedsMap.h ${CURRENT_SOURCE_DIR}/LedSpiDevice.h + ${CURRENT_SOURCE_DIR}/LedRs232Device.h ${CURRENT_SOURCE_DIR}/LedDeviceTest.h ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h ${CURRENT_SOURCE_DIR}/LedDeviceLdp6803.h @@ -37,6 +38,7 @@ SET(Hyperion_SOURCES ${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp ${CURRENT_SOURCE_DIR}/LedSpiDevice.cpp + ${CURRENT_SOURCE_DIR}/LedRs232Device.cpp ${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp ${CURRENT_SOURCE_DIR}/LedDeviceLdp6803.cpp diff --git a/libsrc/hyperion/LedRs232Device.cpp b/libsrc/hyperion/LedRs232Device.cpp new file mode 100644 index 00000000..a7ec5ff7 --- /dev/null +++ b/libsrc/hyperion/LedRs232Device.cpp @@ -0,0 +1,62 @@ + +// STL includes +#include +#include +#include + +// Local Hyperion includes +#include "LedRs232Device.h" + + +LedRs232Device::LedRs232Device(const std::string& outputDevice, const unsigned baudrate) : + mDeviceName(outputDevice), + mBaudRate_Hz(baudrate), + _rs232Port() +{ + // empty +} + +LedRs232Device::~LedRs232Device() +{ + if (_rs232Port.isOpen()) + { + _rs232Port.close(); + } +} + +int LedRs232Device::open() +{ + try + { + _rs232Port.setPort(mDeviceName); + _rs232Port.setBaudrate(mBaudRate_Hz); + _rs232Port.open(); + } + catch (const std::exception& e) + { + std::cerr << "Unable to open RS232 device (" << e.what() << ")" << std::endl; + return -1; + } + + return 0; +} + +int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data) +{ + if (!_rs232Port.isOpen()) + { + return -1; + } + + try + { + _rs232Port.write(data, size); + } + catch (const std::exception& e) + { + std::cerr << "Unable to write to RS232 device (" << e.what() << ")" << std::endl; + return -1; + } + + return 0; +} diff --git a/libsrc/hyperion/LedRs232Device.h b/libsrc/hyperion/LedRs232Device.h new file mode 100644 index 00000000..5e3236f3 --- /dev/null +++ b/libsrc/hyperion/LedRs232Device.h @@ -0,0 +1,54 @@ +#pragma once + +// Serial includes +#include + +// Hyperion includes +#include + +/// +/// The LedRs232Device implements an abstract base-class for LedDevices using a RS232-device. +/// +class LedRs232Device : public LedDevice +{ +public: + /// + /// Constructs the LedDevice attached to a RS232-device + /// + /// @param[in] outputDevice The name of the output device (eg '/etc/ttyS0') + /// @param[in] baudrate The used baudrate for writing to the output device + /// + LedRs232Device(const std::string& outputDevice, const unsigned baudrate); + + /// + /// Destructor of the LedDevice; closes the output device if it is open + /// + virtual ~LedRs232Device(); + + /// + /// Opens and configures the output device + /// + /// @return Zero on succes else negative + /// + int open(); + +protected: + /** + * Writes the given bytes to the RS232-device and + * + * @param[in[ size The length of the data + * @param[in] data The data + * + * @return Zero on succes else negative + */ + int writeBytes(const unsigned size, const uint8_t *data); + +private: + /// The name of the output device + const std::string mDeviceName; + /// The used baudrate of the output device + const int mBaudRate_Hz; + + /// The RS232 serial-device + serial::Serial _rs232Port; +}; diff --git a/libsrc/hyperion/LedSpiDevice.h b/libsrc/hyperion/LedSpiDevice.h index 51d03bfb..4b47b7d8 100644 --- a/libsrc/hyperion/LedSpiDevice.h +++ b/libsrc/hyperion/LedSpiDevice.h @@ -17,6 +17,8 @@ public: /// /// @param[in] outputDevice The name of the output device (eg '/etc/SpiDev.0.0') /// @param[in] baudrate The used baudrate for writing to the output device + /// @param[in] latchTime_ns The latch-time to latch in the values across the SPI-device (negative + /// means no latch required) [ns] /// LedSpiDevice(const std::string& outputDevice, const unsigned baudrate, const int latchTime_ns = -1); @@ -33,17 +35,15 @@ public: int open(); protected: - /** - * Writes the given bytes/bits to the SPI-device and sleeps the latch time to ensure that the - * values are latched. - * - * @param[in[ size The length of the data - * @param[in] data The data - * @param[in] latchTime_ns The latch-time to latch in the values across the SPI-device (negative - * means no latch required) [ns] - * - * @return Zero on succes else negative - */ + /// + /// Writes the given bytes/bits to the SPI-device and sleeps the latch time to ensure that the + /// values are latched. + /// + /// @param[in[ size The length of the data + /// @param[in] data The data + /// + /// @return Zero on succes else negative + /// int writeBytes(const unsigned size, const uint8_t *data); private: